Merge "Add CHANGE_SCREEN_BELOW_RELATED_INFO_BLOCK extension point"
diff --git a/.buckconfig b/.buckconfig
index 61c28e4..f4c17e3 100644
--- a/.buckconfig
+++ b/.buckconfig
@@ -25,7 +25,7 @@
   src_roots = java, resources, src
 
 [project]
-  ignore = .git, eclipse-out
+  ignore = .git, eclipse-out, lib/jgit
   parallel_parsing = true
 
 [cache]
diff --git a/.buckversion b/.buckversion
index 561a769..f5fe016 100644
--- a/.buckversion
+++ b/.buckversion
@@ -1 +1 @@
-ca8d6cbac373a690f543c5159eec0116e76187a9
+e64a2e2ada022f81e42be750b774024469551398
diff --git a/Documentation/access-control.txt b/Documentation/access-control.txt
index 57e7bf7..0123724 100644
--- a/Documentation/access-control.txt
+++ b/Documentation/access-control.txt
@@ -99,21 +99,14 @@
 [[administrators]]
 === Administrators
 
-This is the Gerrit "root" identity. The capability
-link:access-control.html#capability_administrateServer['Administrate Server']
-is assigned to this predefined group on Gerrit site creation.
+This is a predefined group, created on Gerrit site initialization, that
+has the capability link:access-control.html#capability_administrateServer[
+'Administrate Server'] assigned.
 
-Users in the 'Administrators' group can perform any action under
-the Admin menu, to any group or project, without further validation
-or any other access controls.  In most installations only those
-users who have direct filesystem and database access would be
-placed into this group.
-
-Membership in the 'Administrators' group does not imply any other
-access rights.  Administrators do not automatically get code review
-approval or submit rights in projects.  This is a feature designed
-to permit administrative users to otherwise access Gerrit as any
-other normal user would, without needing two different accounts.
+It is a normal Gerrit group without magic. This means if you remove
+the 'Administrate Server' capability from it, its members are no longer
+Gerrit administrators, despite the group name. The group may also be
+renamed.
 
 
 [[non-interactive_users]]
@@ -1175,10 +1168,19 @@
 === Administrate Server
 
 This is in effect the owner and administrator role of the Gerrit
-instance.  Any members of a group granted this capability will be
+instance. Any members of a group granted this capability will be
 able to grant any access right to any group. They will also have all
 capabilities granted to them automatically.
 
+In most installations only those users who have direct filesystem and
+database access should be granted this capability.
+
+This capability does not imply any other access rights. Users that have
+this capability do not automatically get code review approval or submit
+rights in projects. This is a feature designed to permit administrative
+users to otherwise access Gerrit as any other normal user would,
+without needing two different accounts.
+
 
 [[capability_batchChangesLimit]]
 === Batch Changes Limit
diff --git a/Documentation/cmd-review.txt b/Documentation/cmd-review.txt
index 0590337..c3d8651 100644
--- a/Documentation/cmd-review.txt
+++ b/Documentation/cmd-review.txt
@@ -19,6 +19,7 @@
   [--delete]
   [--verified <N>] [--code-review <N>]
   [--label Label-Name=<N>]
+  [--tag TAG]
   {COMMIT | CHANGEID,PATCHSET}...
 --
 
@@ -134,6 +135,15 @@
 	permitted for the user, or the vote is on an outdated or closed patch set,
 	return an error instead of silently discarding the vote.
 
+--tag::
+-t::
+  Apply a 'TAG' to the change message, votes, and inline comments. The 'TAG'
+  can represent an external system like CI that does automated verification
+  of the change. Comments with specific 'TAG' values can be filtered out in
+  the web UI.
+  NOTE: To apply different tags on on different votes/comments multiple
+  invocations of the SSH command are required.
+
 == ACCESS
 Any user who has configured an SSH key.
 
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 59830cc..cd9ee3e 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -955,7 +955,7 @@
 Default is "Submit all ${topicSize} changes of the same topic (${submitSize}
 changes including ancestors and other changes related by topic)".
 
-[[change.submitWholeTopic]]change.submitWholeTopic (*Experimental*)::
+[[change.submitWholeTopic]]change.submitWholeTopic::
 +
 Determines if the submit button submits the whole topic instead of
 just the current change.
diff --git a/Documentation/error-messages.txt b/Documentation/error-messages.txt
index 6ad7ac5..2632254 100644
--- a/Documentation/error-messages.txt
+++ b/Documentation/error-messages.txt
@@ -31,7 +31,7 @@
 * link:error-permission-denied.html[Permission denied (publickey)]
 * link:error-prohibited-by-gerrit.html[prohibited by Gerrit]
 * link:error-project-not-found.html[Project not found: ...]
-* link:error-squash-commits-first.html[squash commits first]
+* link:error-same-change-id-in-multiple-changes.html[same Change-Id in multiple changes]
 * link:error-upload-denied.html[Upload denied for project \'...']
 * link:error-not-allowed-to-upload-merges.html[you are not allowed to upload merges]
 
diff --git a/Documentation/error-squash-commits-first.txt b/Documentation/error-same-change-id-in-multiple-changes.txt
similarity index 94%
rename from Documentation/error-squash-commits-first.txt
rename to Documentation/error-same-change-id-in-multiple-changes.txt
index 4069d5b..b6aad69 100644
--- a/Documentation/error-squash-commits-first.txt
+++ b/Documentation/error-same-change-id-in-multiple-changes.txt
@@ -1,4 +1,4 @@
-= squash commits first
+= same Change-Id in multiple changes
 
 With this error message Gerrit rejects to push a commit if it
 contains the same Change-Id as a predecessor commit.
@@ -50,8 +50,10 @@
   Writing objects: 100% (6/6), 558 bytes, done.
   Total 6 (delta 0), reused 0 (delta 0)
   To ssh://JohnDoe@host:29418/myProject
-   ! [remote rejected] HEAD -> refs/for/master (squash commits first)
+  ! [remote rejected] HEAD -> refs/for/master (same Change-Id in multiple changes.
+  Squash the commits with the same Change-Id or ensure Change-Ids are unique for each commit)
   error: failed to push some refs to 'ssh://JohnDoe@host:29418/myProject'
+
 ----
 
 If it was the intention to rework a change and push a new patch
diff --git a/Documentation/pgm-init.txt b/Documentation/pgm-init.txt
index 9fe813b..9dea161 100644
--- a/Documentation/pgm-init.txt
+++ b/Documentation/pgm-init.txt
@@ -11,7 +11,8 @@
 	[--no-auto-start]
 	[--list-plugins]
 	[--install-plugin=<PLUGIN_NAME>]
-        [--dev]
+	[--install-all-plugins]
+	[--dev]
 	[--skip-all-downloads]
 	[--skip-download=<LIBRARY_NAME>]
 --
@@ -30,10 +31,10 @@
 	configuration defaults are chosen based on the whims of
 	the Gerrit developers.
 +
-If during a schema migration unused objects (e.g. tables, columns)
-are detected they are *not* automatically dropped, but only a list of
-SQL statements to drop these objects is provided. To drop the unused
-objects these SQL statements have to be executed manually.
+	If during a schema migration unused objects (e.g. tables, columns)
+	are detected they are *not* automatically dropped, but only a list of
+	SQL statements to drop these objects is provided. To drop the unused
+	objects these SQL statements have to be executed manually.
 
 --no-auto-start::
 	Don't automatically start the daemon after initializing a
@@ -49,10 +50,16 @@
 --list-plugins::
 	Print names of plugins that can be installed during init process.
 
+--install-all-plugins::
+	Automatically install all plugins from gerrit.war without asking.
+	This option also works in batch mode. This option cannot be supplied
+	alongside --install-plugin.
+
 --install-plugin::
 	Automatically install plugin with given name without asking.
-	This option may be supplied more than once to install multiple
-	plugins.
+	This option also works in batch mode. This option may be supplied
+	more than once to install multiple plugins. This option cannot be
+	supplied alongside --install-all-plugins.
 
 --dev::
 	Install in developer mode. Default configuration settings are
diff --git a/Documentation/rest-api-accounts.txt b/Documentation/rest-api-accounts.txt
index e6dec40..06520e4 100644
--- a/Documentation/rest-api-accounts.txt
+++ b/Documentation/rest-api-accounts.txt
@@ -1361,6 +1361,7 @@
     "key_map_type": "VIM",
     "tab_size": 4,
     "line_length": 80,
+    "indent_unit": 2,
     "cursor_blink_rate": 530,
     "hide_top_menu": true,
     "show_whitespace_errors": true,
@@ -1391,6 +1392,7 @@
     "key_map_type": "VIM",
     "tab_size": 4,
     "line_length": 80,
+    "indent_unit": 2,
     "cursor_blink_rate": 530,
     "hide_top_menu": true,
     "show_tabs": true,
@@ -1812,11 +1814,13 @@
 `ELEGANT`, `NEAT`. Dark themes `MIDNIGHT`, `NIGHT`, `TWILIGHT`.
 |`key_map_type`                ||
 The CodeMirror key map. Currently only a subset of key maps are
-supported: `DEFAULT`, `EMACS`, `VIM`.
+supported: `DEFAULT`, `EMACS`, `SUBLIME`, `VIM`.
 |`tab_size`                    ||
 Number of spaces that should be used to display one tab.
 |`line_length`                 ||
 Number of characters that should be displayed per line.
+|`indent_unit`                 ||
+Number of spaces that should be used for auto-indent.
 |`cursor_blink_rate`           ||
 Half-period in milliseconds used for cursor blinking.
 Setting it to 0 disables cursor blinking.
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index 51ba60f..87cccab 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -2721,6 +2721,7 @@
   Content-Type: application/json; charset=UTF-8
 
   {
+    "tag": "jenkins",
     "message": "Some nits need to be fixed.",
     "labels": {
       "Code-Review": -1
@@ -3970,6 +3971,11 @@
 permitted to vote on that label.
 |`date`        |optional|
 The time and date describing when the approval was made.
+|`tag`                 |optional|
+Value of the `tag` field from link:#review-input[ReviewInput] set
+while posting the review.
+NOTE: To apply different tags on on different votes/comments multiple
+invocations of the REST call are required.
 |===========================
 
 [[change-edit-input]]
@@ -4132,6 +4138,11 @@
 |`date`            ||
 The link:rest-api.html#timestamp[timestamp] this message was posted.
 |`message`            ||The text left by the user.
+|`tag`                 |optional|
+Value of the `tag` field from link:#review-input[ReviewInput] set
+while posting the review.
+NOTE: To apply different tags on on different votes/comments multiple
+invocations of the REST call are required.
 |`_revision_number`    |optional|
 Which patchset (if any) generated this message.
 |==================================
@@ -4182,6 +4193,11 @@
 The author of the message as an
 link:rest-api-accounts.html#account-info[AccountInfo] entity. +
 Unset for draft comments, assumed to be the calling user.
+|`tag`                 |optional|
+Value of the `tag` field from link:#review-input[ReviewInput] set
+while posting the review.
+NOTE: To apply different tags on on different votes/comments multiple
+invocations of the REST call are required.
 |===========================
 
 [[comment-input]]
@@ -4715,6 +4731,11 @@
 |Field Name               ||Description
 |`message`                |optional|
 The message to be added as review comment.
+|`tag`                    |optional|
+Apply this tag to the review comment message, votes, and inline
+comments. Tags may be used by CI or other automated systems to
+distinguish them from human reviews. Comments with specific tag
+values can be filtered out in the web UI.
 |`labels`                 |optional|
 The votes that should be added to the revision as a map that maps the
 label names to the voting values.
@@ -4893,6 +4914,11 @@
 API]. Using this option requires
 link:access-control.html#category_submit_on_behalf_of[Submit (On Behalf Of)]
 permission on the branch.
+|`notify`|optional|
+Notify handling that defines to whom email notifications should be sent after
+the change is submitted. +
+Allowed values are `NONE`, `OWNER`, `OWNER_REVIEWERS` and `ALL`. +
+If not set, the default is `ALL`.
 |===========================
 
 [[submit-record]]
diff --git a/ReleaseNotes/ReleaseNotes-2.13.txt b/ReleaseNotes/ReleaseNotes-2.13.txt
index aba6131..68a7ea2 100644
--- a/ReleaseNotes/ReleaseNotes-2.13.txt
+++ b/ReleaseNotes/ReleaseNotes-2.13.txt
@@ -82,4 +82,26 @@
 Upgrades
 --------
 
-* Upgrade Lucene to 5.3.1
+* Upgrade CodeMirror to 5.13.4
+
+* Upgrade Guava to 19.0
+
+* Upgrade Gson to 2.6.2
+
+* Upgrade gwtjsonrpc to version 1.8
+
+* Upgrade gwtorm to 1.15
+
+* Upgrade javassist.jar to 3.18.1
+
+* Upgrade Jetty to 9.2.14.v20151106
+
+* Upgrade JGit to 4.3.0.201604071810-r
+
+* Upgrade Lucene to 5.4.1
+
+* Upgrade mina to 2.10
+
+* Upgrade sshd-core to 1.2.0
+
+* Upgrade Truth to 0.28
diff --git a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
index 9cf1515..f490cad 100644
--- a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
+++ b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
@@ -617,6 +617,10 @@
     projectCache.evict(cfg.getProject());
   }
 
+  protected void saveProjectConfig(ProjectConfig cfg) throws Exception {
+    saveProjectConfig(project, cfg);
+  }
+
   protected void grant(String permission, Project.NameKey project, String ref)
       throws RepositoryNotFoundException, IOException, ConfigInvalidException {
     grant(permission, project, ref, false);
diff --git a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AccountCreator.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AccountCreator.java
index 2a65333..ee0688b 100644
--- a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AccountCreator.java
+++ b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AccountCreator.java
@@ -160,12 +160,12 @@
     return new AccountExternalId.Key(AccountExternalId.SCHEME_MAILTO, email);
   }
 
-  private static KeyPair genSshKey() throws JSchException {
+  public static KeyPair genSshKey() throws JSchException {
     JSch jsch = new JSch();
     return KeyPair.genKeyPair(jsch, KeyPair.RSA);
   }
 
-  private static String publicKey(KeyPair sshKey, String comment)
+  public static String publicKey(KeyPair sshKey, String comment)
       throws UnsupportedEncodingException {
     ByteArrayOutputStream out = new ByteArrayOutputStream();
     sshKey.writePublicKey(out, comment);
diff --git a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/GerritServer.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/GerritServer.java
index 08977f0..c4e636b 100644
--- a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/GerritServer.java
+++ b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/GerritServer.java
@@ -151,7 +151,7 @@
         public Void call() throws Exception {
           int rc = daemon.main(new String[] {
               "-d", site.getPath(),
-              "--headless", "--console-log", "--show-stack-trace"});
+              "--headless", "--console-log", "--show-stack-trace",});
           if (rc != 0) {
             System.err.println("Failed to start Gerrit daemon");
             serverStarted.reset();
@@ -172,7 +172,7 @@
     Init init = new Init();
     int rc = init.main(new String[] {
         "-d", tmp.getPath(), "--batch", "--no-auto-start",
-        "--skip-plugins"});
+        "--skip-plugins",});
     if (rc != 0) {
       throw new RuntimeException("Couldn't initialize site");
     }
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/UseGerritConfigAnnotationTest.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/UseGerritConfigAnnotationTest.java
index f4d156c..2f50480 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/UseGerritConfigAnnotationTest.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/UseGerritConfigAnnotationTest.java
@@ -29,15 +29,15 @@
   Config serverConfig;
 
   @Test
-  @GerritConfig(name="x.y", value="z")
+  @GerritConfig(name = "x.y", value = "z")
   public void testOne() {
     assertThat(serverConfig.getString("x", null, "y")).isEqualTo("z");
   }
 
   @Test
   @GerritConfigs({
-      @GerritConfig(name="x.y", value="z"),
-      @GerritConfig(name="a.b", value="c")
+      @GerritConfig(name = "x.y", value = "z"),
+      @GerritConfig(name = "a.b", value = "c")
   })
   public void testMultiple() {
     assertThat(serverConfig.getString("x", null, "y")).isEqualTo("z");
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java
index ac5b262..59f0150 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java
@@ -30,11 +30,13 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.io.BaseEncoding;
 import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.AccountCreator;
 import com.google.gerrit.acceptance.PushOneCommit;
 import com.google.gerrit.acceptance.TestAccount;
 import com.google.gerrit.extensions.api.accounts.EmailInput;
 import com.google.gerrit.extensions.common.AccountInfo;
 import com.google.gerrit.extensions.common.GpgKeyInfo;
+import com.google.gerrit.extensions.common.SshKeyInfo;
 import com.google.gerrit.extensions.restapi.BadRequestException;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
@@ -333,6 +335,28 @@
         ImmutableList.of(key2.getKeyIdString()));
   }
 
+  @Test
+  public void sshKeys() throws Exception {
+    // The test account should initially have exactly one ssh key
+    List<SshKeyInfo> info = gApi.accounts().self().listSshKeys();
+    assertThat(info).hasSize(1);
+    SshKeyInfo key = info.get(0);
+    String inital = AccountCreator.publicKey(admin.sshKey, admin.email);
+    assertThat(key.sshPublicKey).isEqualTo(inital);
+
+    // Add a new key
+    String newKey = AccountCreator.publicKey(
+        AccountCreator.genSshKey(), admin.email);
+    gApi.accounts().self().addSshKey(newKey);
+    info = gApi.accounts().self().listSshKeys();
+    assertThat(info).hasSize(2);
+
+    // Add an existing key again
+    gApi.accounts().self().addSshKey(inital);
+    info = gApi.accounts().self().listSshKeys();
+    assertThat(info).hasSize(3);
+  }
+
   private PGPPublicKey getOnlyKeyFromStore(TestKey key) throws Exception {
     try (PublicKeyStore store = publicKeyStoreProvider.get()) {
       Iterable<PGPPublicKeyRing> keys = store.get(key.getKeyId());
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/DiffPreferencesIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/DiffPreferencesIT.java
index 14eaa90..f1b8a2d 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/DiffPreferencesIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/DiffPreferencesIT.java
@@ -45,6 +45,7 @@
     assertThat(o.showTabs).isEqualTo(d.showTabs);
     assertThat(o.showWhitespaceErrors).isEqualTo(d.showWhitespaceErrors);
     assertThat(o.skipDeleted).isNull();
+    assertThat(o.skipUnchanged).isNull();
     assertThat(o.skipUncommented).isNull();
     assertThat(o.syntaxHighlighting).isEqualTo(d.syntaxHighlighting);
     assertThat(o.hideTopMenu).isNull();
@@ -76,6 +77,7 @@
     i.showTabs ^= true;
     i.showWhitespaceErrors ^= true;
     i.skipDeleted ^= true;
+    i.skipUnchanged ^= true;
     i.skipUncommented ^= true;
     i.syntaxHighlighting ^= true;
     i.hideTopMenu ^= true;
@@ -101,6 +103,7 @@
     assertThat(o.showTabs).isNull();
     assertThat(o.showWhitespaceErrors).isNull();
     assertThat(o.skipDeleted).isEqualTo(i.skipDeleted);
+    assertThat(o.skipUnchanged).isEqualTo(i.skipUnchanged);
     assertThat(o.skipUncommented).isEqualTo(i.skipUncommented);
     assertThat(o.syntaxHighlighting).isNull();
     assertThat(o.hideTopMenu).isEqualTo(i.hideTopMenu);
@@ -130,6 +133,7 @@
     assertThat(a.showTabs).isNull();
     assertThat(a.showWhitespaceErrors).isNull();
     assertThat(a.skipDeleted).isEqualTo(o.skipDeleted);
+    assertThat(a.skipUnchanged).isEqualTo(o.skipUnchanged);
     assertThat(a.skipUncommented).isEqualTo(o.skipUncommented);
     assertThat(a.syntaxHighlighting).isNull();
     assertThat(a.hideTopMenu).isEqualTo(o.hideTopMenu);
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/EditPreferencesIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/EditPreferencesIT.java
index fd810c4..df85d0f 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/EditPreferencesIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/EditPreferencesIT.java
@@ -33,6 +33,7 @@
         .getEditPreferences();
 
     assertThat(out.lineLength).isEqualTo(100);
+    assertThat(out.indentUnit).isEqualTo(2);
     assertThat(out.tabSize).isEqualTo(8);
     assertThat(out.cursorBlinkRate).isEqualTo(0);
     assertThat(out.hideTopMenu).isNull();
@@ -47,6 +48,7 @@
 
     // change some default values
     out.lineLength = 80;
+    out.indentUnit = 4;
     out.tabSize = 4;
     out.cursorBlinkRate = 500;
     out.hideTopMenu = true;
@@ -80,6 +82,7 @@
   private void assertEditPreferences(EditPreferencesInfo out,
       EditPreferencesInfo in) throws Exception {
     assertThat(out.lineLength).isEqualTo(in.lineLength);
+    assertThat(out.indentUnit).isEqualTo(in.indentUnit);
     assertThat(out.tabSize).isEqualTo(in.tabSize);
     assertThat(out.cursorBlinkRate).isEqualTo(in.cursorBlinkRate);
     assertThat(out.hideTopMenu).isEqualTo(in.hideTopMenu);
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
index cf866e1..2308b39 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -1074,7 +1074,7 @@
     pushFactory.create(db, admin.getIdent(), testRepo, PushOneCommit.SUBJECT,
         "b.txt", "4711", r.getChangeId()).to("refs/for/master").assertOkStatus();
     ChangeInfo c = gApi.changes().id(r.getChangeId()).get();
-    try (Repository repo = repoManager.openMetadataRepository(project);
+    try (Repository repo = repoManager.openRepository(project);
         RevWalk rw = new RevWalk(repo)) {
       RevCommit commitPatchSetCreation = rw.parseCommit(
           repo.exactRef(ChangeNoteUtil.changeRefName(new Change.Id(c._number)))
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractPushForReview.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractPushForReview.java
index 638d20e..205a3bb 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractPushForReview.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractPushForReview.java
@@ -39,7 +39,6 @@
 import com.google.gerrit.extensions.common.LabelInfo;
 import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.server.git.MetaDataUpdate;
 import com.google.gerrit.server.git.ProjectConfig;
 import com.google.gerrit.server.group.SystemGroupBackend;
 import com.google.gerrit.server.project.Util;
@@ -88,12 +87,6 @@
     grant(Permission.LABEL + "Patch-Set-Lock", project, "refs/heads/*");
   }
 
-  private void saveProjectConfig(ProjectConfig cfg) throws Exception {
-    try (MetaDataUpdate md = metaDataUpdateFactory.create(project)) {
-      cfg.commit(md);
-    }
-  }
-
   protected void selectProtocol(Protocol p) throws Exception {
     String url;
     switch (p) {
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeMessagesIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeMessagesIT.java
index 91f2962..40b0391 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeMessagesIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeMessagesIT.java
@@ -81,13 +81,34 @@
     assertMessage(secondMessage, it.next().message);
   }
 
+  @Test
+  public void postMessageWithTag() throws Exception {
+    String changeId = createChange().getChangeId();
+    String tag = "jenkins";
+    String msg = "Message with tag.";
+    postMessage(changeId, msg, tag);
+    ChangeInfo c = get(changeId);
+    assertThat(c.messages).isNotNull();
+    assertThat(c.messages).hasSize(2);
+    Iterator<ChangeMessageInfo> it = c.messages.iterator();
+    assertThat(it.next().message).isEqualTo("Uploaded patch set 1.");
+    ChangeMessageInfo actual = it.next();
+    assertMessage(msg, actual.message);
+    assertThat(actual.tag).isEqualTo(tag);
+  }
+
   private void assertMessage(String expected, String actual) {
     assertThat(actual).isEqualTo("Patch Set 1:\n\n" + expected);
   }
 
   private void postMessage(String changeId, String msg) throws Exception {
+    postMessage(changeId, msg, null);
+  }
+
+  private void postMessage(String changeId, String msg, String tag) throws Exception {
     ReviewInput in = new ReviewInput();
     in.message = msg;
+    in.tag = tag;
     gApi.changes().id(changeId).current().review(in);
   }
 }
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ConfigChangeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ConfigChangeIT.java
index c4216cd..b8f0ec9 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ConfigChangeIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ConfigChangeIT.java
@@ -103,7 +103,7 @@
       assertThat(e).hasMessage(
           "Failed to submit 1 change due to the following problems:\n"
           + "Change " + n + ": Change contains a project configuration that"
-          +" changes the parent project.\n"
+          + " changes the parent project.\n"
           + "The change must be submitted by a Gerrit administrator.");
     }
 
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java
index a714f6e..8153ffb 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java
@@ -119,7 +119,7 @@
     assume().that(notesMigration.enabled()).isTrue();
 
     ChangeInfo c = assertCreateSucceeds(newChangeInput(ChangeStatus.NEW));
-    try (Repository repo = repoManager.openMetadataRepository(project);
+    try (Repository repo = repoManager.openRepository(project);
         RevWalk rw = new RevWalk(repo)) {
       RevCommit commit = rw.parseCommit(
           repo.exactRef(ChangeNoteUtil.changeRefName(new Change.Id(c._number)))
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/DeleteDraftPatchSetIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/DeleteDraftPatchSetIT.java
index b5875bb..50af8e6 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/DeleteDraftPatchSetIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/DeleteDraftPatchSetIT.java
@@ -107,7 +107,7 @@
 
   private Ref getDraftRef(TestAccount account, Change.Id changeId)
       throws Exception {
-    try (Repository repo = repoManager.openMetadataRepository(allUsers)) {
+    try (Repository repo = repoManager.openRepository(allUsers)) {
       return repo.exactRef(RefNames.refsDraftComments(account.id, changeId));
     }
   }
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/MoveChangeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/MoveChangeIT.java
index df1ebfd..c164786 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/MoveChangeIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/MoveChangeIT.java
@@ -32,7 +32,6 @@
 import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.reviewdb.client.Branch;
-import com.google.gerrit.server.git.MetaDataUpdate;
 import com.google.gerrit.server.git.ProjectConfig;
 import com.google.gerrit.server.group.SystemGroupBackend;
 import com.google.gerrit.server.project.Util;
@@ -45,7 +44,7 @@
 @NoHttpd
 public class MoveChangeIT extends AbstractDaemonTest {
   @Test
-  public void moveChange_shortRef() throws Exception {
+  public void moveChangeWithShortRef() throws Exception {
     // Move change to a different branch using short ref name
     PushOneCommit.Result r = createChange();
     Branch.NameKey newBranch =
@@ -56,7 +55,7 @@
   }
 
   @Test
-  public void moveChange_fullRef() throws Exception {
+  public void moveChangeWithFullRef() throws Exception {
     // Move change to a different branch using full ref name
     PushOneCommit.Result r = createChange();
     Branch.NameKey newBranch =
@@ -94,7 +93,7 @@
   }
 
   @Test
-  public void moveChange_sameChangeId() throws Exception {
+  public void moveChangeToSameChangeId() throws Exception {
     // Move change to a branch with existing change with same change ID
     PushOneCommit.Result r = createChange();
     Branch.NameKey newBranch =
@@ -160,7 +159,7 @@
   }
 
   @Test
-  public void moveChangeToBranch_WithoutUploadPerms() throws Exception {
+  public void moveChangeToBranchWithoutUploadPerms() throws Exception {
     // Move change to a destination where user doesn't have upload permissions
     PushOneCommit.Result r = createChange();
     Branch.NameKey newBranch =
@@ -175,7 +174,7 @@
   }
 
   @Test
-  public void moveChangeFromBranch_WithoutAbandonPerms() throws Exception {
+  public void moveChangeFromBranchWithoutAbandonPerms() throws Exception {
     // Move change for which user does not have abandon permissions
     PushOneCommit.Result r = createChange();
     Branch.NameKey newBranch =
@@ -218,7 +217,7 @@
   }
 
   @Test
-  public void moveChange_WithCurrentPatchSetLocked() throws Exception {
+  public void moveChangeWithCurrentPatchSetLocked() throws Exception {
     // Move change that is locked
     PushOneCommit.Result r = createChange();
     Branch.NameKey newBranch =
@@ -241,12 +240,6 @@
     move(r.getChangeId(), newBranch.get());
   }
 
-  private void saveProjectConfig(ProjectConfig cfg) throws Exception {
-    try (MetaDataUpdate md = metaDataUpdateFactory.create(project)) {
-      cfg.commit(md);
-    }
-  }
-
   private void move(int changeNum, String destination)
       throws RestApiException {
     gApi.changes().id(changeNum).move(destination);
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByRebaseIfNecessaryIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByRebaseIfNecessaryIT.java
index 494ff3e..1687929 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByRebaseIfNecessaryIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitByRebaseIfNecessaryIT.java
@@ -15,6 +15,8 @@
 package com.google.gerrit.acceptance.rest.change;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.acceptance.GitUtil.getChangeId;
+import static com.google.gerrit.acceptance.GitUtil.pushHead;
 
 import com.google.common.collect.Iterables;
 import com.google.gerrit.acceptance.PushOneCommit;
@@ -232,4 +234,31 @@
       return c;
     }
   }
+
+  @Test
+  public void submitAfterReorderOfCommits() throws Exception {
+    // Create two commits and push.
+    RevCommit c1 = commitBuilder()
+        .add("a.txt", "1")
+        .message("subject: 1")
+        .create();
+    RevCommit c2 = commitBuilder()
+        .add("b.txt", "2")
+        .message("subject: 2")
+        .create();
+    pushHead(testRepo, "refs/for/master", false);
+
+    String id1 = getChangeId(testRepo, c1).get();
+    String id2 = getChangeId(testRepo, c2).get();
+
+    // Swap the order of commits and push again.
+    testRepo.reset("HEAD~2");
+    testRepo.cherryPick(c2);
+    testRepo.cherryPick(c1);
+    pushHead(testRepo, "refs/for/master", false);
+
+    approve(id1);
+    approve(id2);
+    submit(id1);
+  }
 }
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitResolvingMergeCommitIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitResolvingMergeCommitIT.java
index 5a6c36a..d5b6f14 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitResolvingMergeCommitIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SubmitResolvingMergeCommitIT.java
@@ -92,10 +92,10 @@
     approve(g.getChangeId());
     approve(h.getChangeId());
 
-    assertMergeable(e.getChange(), true);
-    assertMergeable(f.getChange(), true);
-    assertMergeable(g.getChange(), false);
-    assertMergeable(h.getChange(), false);
+    assertMergeable(e.getChange());
+    assertMergeable(f.getChange());
+    assertNotMergeable(g.getChange());
+    assertNotMergeable(h.getChange());
 
     PushOneCommit.Result m = createChange("M", "new.txt", "Resolved conflict",
         ImmutableList.of(d.getCommit(), h.getCommit()));
@@ -103,7 +103,7 @@
 
     assertChangeSetMergeable(m.getChange(), true);
 
-    assertMergeable(m.getChange(), true);
+    assertMergeable(m.getChange());
     submit(m.getChangeId());
 
     assertMerged(e.getChangeId());
@@ -138,15 +138,15 @@
     PushOneCommit.Result g = createChange("G", "new.txt", "Conflicting line #2",
         ImmutableList.of(f.getCommit()));
 
-    assertMergeable(e.getChange(), true);
+    assertMergeable(e.getChange());
 
     approve(a.getChangeId());
     approve(b.getChangeId());
     submit(b.getChangeId());
 
-    assertMergeable(e.getChange(), false);
-    assertMergeable(f.getChange(), true);
-    assertMergeable(g.getChange(), true);
+    assertNotMergeable(e.getChange());
+    assertMergeable(f.getChange());
+    assertMergeable(g.getChange());
 
     approve(c.getChangeId());
     approve(d.getChangeId());
@@ -156,7 +156,7 @@
     approve(f.getChangeId());
     approve(g.getChangeId());
 
-    assertMergeable(g.getChange(), false);
+    assertNotMergeable(g.getChange());
     assertChangeSetMergeable(g.getChange(), false);
   }
 
@@ -278,7 +278,7 @@
     approve(c.getChangeId());
     approve(e.getChangeId());
     approve(d.getChangeId());
-    assertMergeable(d.getChange(), false);
+    assertNotMergeable(d.getChange());
     assertChangeSetMergeable(d.getChange(), false);
   }
 
@@ -297,10 +297,14 @@
     assertThat(submit.unmergeableChanges(cs).isEmpty()).isEqualTo(expected);
   }
 
-  private void assertMergeable(ChangeData change, boolean expected)
-      throws Exception {
+  private void assertMergeable(ChangeData change) throws Exception {
     change.setMergeable(null);
-    assertThat(change.isMergeable()).isEqualTo(expected);
+    assertThat(change.isMergeable()).isTrue();
+  }
+
+  private void assertNotMergeable(ChangeData change) throws Exception {
+    change.setMergeable(null);
+    assertThat(change.isMergeable()).isFalse();
   }
 
   private void assertMerged(String changeId) throws Exception {
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/ServerInfoIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/ServerInfoIT.java
index a656760..7f5860b 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/ServerInfoIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/ServerInfoIT.java
@@ -15,6 +15,7 @@
 package com.google.gerrit.acceptance.rest.config;
 
 import static com.google.common.truth.Truth.assertThat;
+import static java.nio.charset.StandardCharsets.UTF_8;
 
 import com.google.gerrit.acceptance.AbstractDaemonTest;
 import com.google.gerrit.acceptance.GerritConfig;
@@ -27,6 +28,8 @@
 import com.google.gerrit.server.config.AnonymousCowardNameProvider;
 import com.google.gerrit.server.config.GetServerInfo.ServerInfo;
 
+import java.nio.file.Path;
+import java.nio.file.Files;
 import org.junit.Test;
 
 public class ServerInfoIT extends AbstractDaemonTest {
@@ -107,6 +110,9 @@
     // gitweb
     assertThat(i.gitweb).isNull();
 
+    // plugin
+    assertThat(i.plugin.jsResourcePaths).isEmpty();
+
     // sshd
     assertThat(i.sshd).isNotNull();
 
@@ -118,6 +124,21 @@
   }
 
   @Test
+  @GerritConfig(name = "plugins.allowRemoteAdmin", value = "true")
+  public void serverConfigWithPlugin() throws Exception {
+    Path plugins = tempSiteDir.newFolder("plugins").toPath();
+    Path jsplugin = plugins.resolve("js-plugin-1.js");
+    Files.write(jsplugin, "Gerrit.install(function(self){});\n".getBytes(UTF_8));
+    sshSession.exec("gerrit plugin reload");
+
+    RestResponse r = adminSession.get("/config/server/info/");
+    ServerInfo i = newGson().fromJson(r.getReader(), ServerInfo.class);
+
+    // plugin
+    assertThat(i.plugin.jsResourcePaths).hasSize(1);
+  }
+
+  @Test
   public void serverConfigWithDefaults() throws Exception {
     RestResponse r = adminSession.get("/config/server/info/");
     ServerInfo i = newGson().fromJson(r.getReader(), ServerInfo.class);
@@ -157,6 +178,9 @@
     // gitweb
     assertThat(i.gitweb).isNull();
 
+    // plugin
+    assertThat(i.plugin.jsResourcePaths).isEmpty();
+
     // sshd
     assertThat(i.sshd).isNotNull();
 
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/event/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/event/BUCK
new file mode 100644
index 0000000..49d998c
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/event/BUCK
@@ -0,0 +1,7 @@
+include_defs('//gerrit-acceptance-tests/tests.defs')
+
+acceptance_tests(
+  group = 'server-event',
+  srcs = glob(['*IT.java']),
+  labels = ['server'],
+)
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/event/CommentAddedEventIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/event/CommentAddedEventIT.java
index 3c99dc3..33c7251 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/event/CommentAddedEventIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/event/CommentAddedEventIT.java
@@ -18,7 +18,6 @@
 import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS;
 import static com.google.gerrit.server.project.Util.category;
 import static com.google.gerrit.server.project.Util.value;
-import static org.junit.Assert.fail;
 
 import com.google.gerrit.acceptance.AbstractDaemonTest;
 import com.google.gerrit.acceptance.NoHttpd;
@@ -105,6 +104,20 @@
     saveProjectConfig(project, cfg);
   }
 
+  /* Need to lookup info for the label under test since there can be multiple
+   * labels defined.  By default Gerrit already has a Code-Review label.
+   */
+  private ApprovalAttribute getApprovalAttribute(LabelType label) {
+    ApprovalAttribute[] aa = lastCommentAddedEvent.approvals.get();
+    ApprovalAttribute res = null;
+    for (int i=0; i < aa.length; i++) {
+      if (aa[i].description.equals(label.getName())) {
+        res = aa[i];
+      }
+    }
+    return res;
+  }
+
   @Test
   public void newChangeWithVote() throws Exception {
     saveLabelConfig();
@@ -114,10 +127,9 @@
     ReviewInput reviewInput = new ReviewInput().label(
         label.getName(), (short)-1);
     revision(r).review(reviewInput);
-    String newVote = lastCommentAddedEvent.approvals.get()[0].value;
-    String oldVote = lastCommentAddedEvent.approvals.get()[0].oldValue;
-    assertThat(oldVote).isEqualTo("0");
-    assertThat(newVote).isEqualTo("-1");
+    ApprovalAttribute attr = getApprovalAttribute(label);
+    assertThat(attr.oldValue).isEqualTo("0");
+    assertThat(attr.value).isEqualTo("-1");
     assertThat(lastCommentAddedEvent.comment).isEqualTo(
         String.format("Patch Set 1: %s-1", label.getName()));
   }
@@ -137,10 +149,9 @@
     reviewInput = new ReviewInput().label(
         label.getName(), (short)1);
     revision(r).review(reviewInput);
-    String newVote = lastCommentAddedEvent.approvals.get()[0].value;
-    String oldVote = lastCommentAddedEvent.approvals.get()[0].oldValue;
-    assertThat(oldVote).isEqualTo("0");
-    assertThat(newVote).isEqualTo("1");
+    ApprovalAttribute attr = getApprovalAttribute(label);
+    assertThat(attr.oldValue).isEqualTo("0");
+    assertThat(attr.value).isEqualTo("1");
     assertThat(lastCommentAddedEvent.comment).isEqualTo(
         String.format("Patch Set 2: %s+1", label.getName()));
   }
@@ -155,58 +166,55 @@
     // review with message only, do not apply votes
     ReviewInput reviewInput = new ReviewInput().message(label.getName());
     revision(r).review(reviewInput);
-    // reply message only so votes are excluded from comment
-    assertThat(lastCommentAddedEvent.approvals.get()).isNull();
+    // reply message only so vote is shown as 0
+    ApprovalAttribute attr = getApprovalAttribute(label);
+    assertThat(attr.oldValue).isNull();
+    assertThat(attr.value).isEqualTo("0");
     assertThat(lastCommentAddedEvent.comment).isEqualTo(
         String.format("Patch Set 1:\n\n%s", label.getName()));
 
     // transition from un-voted to -1 vote
     reviewInput = new ReviewInput().label(label.getName(), -1);
     revision(r).review(reviewInput);
-    String newVote = lastCommentAddedEvent.approvals.get()[0].value;
-    String oldVote = lastCommentAddedEvent.approvals.get()[0].oldValue;
-    assertThat(oldVote).isEqualTo("0");
-    assertThat(newVote).isEqualTo("-1");
+    attr = getApprovalAttribute(label);
+    assertThat(attr.oldValue).isEqualTo("0");
+    assertThat(attr.value).isEqualTo("-1");
     assertThat(lastCommentAddedEvent.comment).isEqualTo(
         String.format("Patch Set 1: %s-1", label.getName()));
 
     // transition vote from -1 to 0
     reviewInput = new ReviewInput().label(label.getName(), 0);
     revision(r).review(reviewInput);
-    newVote = lastCommentAddedEvent.approvals.get()[0].value;
-    oldVote = lastCommentAddedEvent.approvals.get()[0].oldValue;
-    assertThat(oldVote).isEqualTo("-1");
-    assertThat(newVote).isEqualTo("0");
+    attr = getApprovalAttribute(label);
+    assertThat(attr.oldValue).isEqualTo("-1");
+    assertThat(attr.value).isEqualTo("0");
     assertThat(lastCommentAddedEvent.comment).isEqualTo(
         String.format("Patch Set 1: -%s", label.getName()));
 
     // transition vote from 0 to 1
     reviewInput = new ReviewInput().label(label.getName(), 1);
     revision(r).review(reviewInput);
-    newVote = lastCommentAddedEvent.approvals.get()[0].value;
-    oldVote = lastCommentAddedEvent.approvals.get()[0].oldValue;
-    assertThat(oldVote).isEqualTo("0");
-    assertThat(newVote).isEqualTo("1");
+    attr = getApprovalAttribute(label);
+    assertThat(attr.oldValue).isEqualTo("0");
+    assertThat(attr.value).isEqualTo("1");
     assertThat(lastCommentAddedEvent.comment).isEqualTo(
         String.format("Patch Set 1: %s+1", label.getName()));
 
     // transition vote from 1 to -1
     reviewInput = new ReviewInput().label(label.getName(), -1);
     revision(r).review(reviewInput);
-    newVote = lastCommentAddedEvent.approvals.get()[0].value;
-    oldVote = lastCommentAddedEvent.approvals.get()[0].oldValue;
-    assertThat(oldVote).isEqualTo("1");
-    assertThat(newVote).isEqualTo("-1");
+    attr = getApprovalAttribute(label);
+    assertThat(attr.oldValue).isEqualTo("1");
+    assertThat(attr.value).isEqualTo("-1");
     assertThat(lastCommentAddedEvent.comment).isEqualTo(
         String.format("Patch Set 1: %s-1", label.getName()));
 
     // review with message only, do not apply votes
     reviewInput = new ReviewInput().message(label.getName());
     revision(r).review(reviewInput);
-    newVote = lastCommentAddedEvent.approvals.get()[0].value;
-    oldVote = lastCommentAddedEvent.approvals.get()[0].oldValue;
-    assertThat(oldVote).isEqualTo(null);  // no vote change so not included
-    assertThat(newVote).isEqualTo("-1");
+    attr = getApprovalAttribute(label);
+    assertThat(attr.oldValue).isEqualTo(null);  // no vote change so not included
+    assertThat(attr.value).isEqualTo("-1");
     assertThat(lastCommentAddedEvent.comment).isEqualTo(
         String.format("Patch Set 1:\n\n%s", label.getName()));
   }
@@ -222,10 +230,27 @@
     ChangeInfo c = get(r.getChangeId());
     LabelInfo q = c.labels.get(label.getName());
     assertThat(q.all).hasSize(1);
+    ApprovalAttribute labelAttr = getApprovalAttribute(label);
+    assertThat(labelAttr.oldValue).isEqualTo("0");
+    assertThat(labelAttr.value).isEqualTo("-1");
     assertThat(lastCommentAddedEvent.comment).isEqualTo(
         String.format("Patch Set 1: %s-1\n\n%s",
             label.getName(), label.getName()));
 
+    // there should be 3 approval labels (label, pLabel, and CRVV)
+    assertThat(lastCommentAddedEvent.approvals.get()).hasLength(3);
+
+    // check the approvals that were not voted on
+    ApprovalAttribute pLabelAttr = getApprovalAttribute(pLabel);
+    assertThat(pLabelAttr.oldValue).isNull();
+    assertThat(pLabelAttr.value).isEqualTo("0");
+
+    LabelType crLabel = LabelType.withDefaultValues("Code-Review");
+    ApprovalAttribute crlAttr = getApprovalAttribute(crLabel);
+    assertThat(crlAttr.oldValue).isNull();
+    assertThat(crlAttr.value).isEqualTo("0");
+
+    // update pLabel approval
     reviewInput = new ReviewInput().label(pLabel.getName(), 1);
     reviewInput.message = pLabel.getName();
     revision(r).review(reviewInput);
@@ -233,21 +258,20 @@
     c = get(r.getChangeId());
     q = c.labels.get(label.getName());
     assertThat(q.all).hasSize(1);
+    pLabelAttr = getApprovalAttribute(pLabel);
+    assertThat(pLabelAttr.oldValue).isEqualTo("0");
+    assertThat(pLabelAttr.value).isEqualTo("1");
     assertThat(lastCommentAddedEvent.comment).isEqualTo(
         String.format("Patch Set 1: %s+1\n\n%s",
             pLabel.getName(), pLabel.getName()));
 
-    assertThat(lastCommentAddedEvent.approvals.get()).hasLength(2);
-    for (ApprovalAttribute approval : lastCommentAddedEvent.approvals.get()) {
-      if (approval.type.equals(label.getName())) {
-        assertThat(approval.value).isEqualTo("-1");
-        assertThat(approval.oldValue).isNull();
-      } else if (approval.type.equals(pLabel.getName())) {
-        assertThat(approval.value).isEqualTo("1");
-        assertThat(approval.oldValue).isEqualTo("0");
-      } else {
-        fail("Unexpected label: " + approval.type);
-      }
-    }
+    // check the approvals that were not voted on
+    labelAttr = getApprovalAttribute(label);
+    assertThat(labelAttr.oldValue).isNull();
+    assertThat(labelAttr.value).isEqualTo("-1");
+
+    crlAttr = getApprovalAttribute(crLabel);
+    assertThat(crlAttr.oldValue).isNull();
+    assertThat(crlAttr.value).isEqualTo("0");
   }
 }
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/ChangeRebuilderIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/ChangeRebuilderIT.java
index 1df074e..f15ff36 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/ChangeRebuilderIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/ChangeRebuilderIT.java
@@ -17,25 +17,35 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.TruthJUnit.assume;
 
+import com.google.common.collect.ImmutableList;
 import com.google.gerrit.acceptance.AbstractDaemonTest;
 import com.google.gerrit.acceptance.AcceptanceTestRequestScope;
 import com.google.gerrit.acceptance.PushOneCommit;
 import com.google.gerrit.acceptance.TestAccount;
+import com.google.gerrit.common.TimeUtil;
 import com.google.gerrit.extensions.api.changes.DraftInput;
+import com.google.gerrit.extensions.api.changes.ReviewInput;
+import com.google.gerrit.extensions.api.changes.ReviewInput.CommentInput;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
+import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.ChangeMessage;
+import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.client.RefNames;
 import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.ChangeUtil;
 import com.google.gerrit.server.PatchLineCommentsUtil;
 import com.google.gerrit.server.change.Rebuild;
 import com.google.gerrit.server.config.AllUsersName;
 import com.google.gerrit.server.notedb.ChangeBundle;
 import com.google.gerrit.server.notedb.ChangeNoteUtil;
+import com.google.gerrit.server.notedb.ChangeNotes;
 import com.google.gerrit.server.notedb.NoteDbChangeState;
 import com.google.gerrit.server.schema.DisabledChangesReviewDbWrapper;
 import com.google.gerrit.testutil.NoteDbChecker;
 import com.google.gerrit.testutil.NoteDbMode;
+import com.google.gerrit.testutil.TestChanges;
 import com.google.gerrit.testutil.TestTimeUtil;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -47,7 +57,10 @@
 import org.junit.Before;
 import org.junit.Test;
 
+import java.sql.Timestamp;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
 public class ChangeRebuilderIT extends AbstractDaemonTest {
@@ -95,6 +108,108 @@
   }
 
   @Test
+  public void publishedComment() throws Exception {
+    PushOneCommit.Result r = createChange();
+    Change.Id id = r.getPatchSetId().getParentKey();
+    putComment(user, id, 1, "comment");
+    checker.rebuildAndCheckChanges(id);
+  }
+
+  @Test
+  public void patchSetWithNullGroups() throws Exception {
+    Timestamp ts = TimeUtil.nowTs();
+    @SuppressWarnings("deprecation")
+    Change c = TestChanges.newChange(project, user.getId(), db.nextChangeId());
+    c.setCreatedOn(ts);
+    c.setLastUpdatedOn(ts);
+    PatchSet ps = TestChanges.newPatchSet(
+        c.currentPatchSetId(), "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
+        user.getId());
+    ps.setCreatedOn(ts);
+    db.changes().insert(Collections.singleton(c));
+    db.patchSets().insert(Collections.singleton(ps));
+
+    assertThat(ps.getGroups()).isEmpty();
+    checker.rebuildAndCheckChanges(c.getId());
+  }
+
+  @Test
+  public void draftComment() throws Exception {
+    PushOneCommit.Result r = createChange();
+    Change.Id id = r.getPatchSetId().getParentKey();
+    putDraft(user, id, 1, "comment");
+    checker.rebuildAndCheckChanges(id);
+  }
+
+  @Test
+  public void draftAndPublishedComment() throws Exception {
+    PushOneCommit.Result r = createChange();
+    Change.Id id = r.getPatchSetId().getParentKey();
+    putDraft(user, id, 1, "draft comment");
+    putComment(user, id, 1, "published comment");
+    checker.rebuildAndCheckChanges(id);
+  }
+
+  @Test
+  public void publishDraftComment() throws Exception {
+    PushOneCommit.Result r = createChange();
+    Change.Id id = r.getPatchSetId().getParentKey();
+    putDraft(user, id, 1, "draft comment");
+    publishDrafts(user, id);
+    checker.rebuildAndCheckChanges(id);
+  }
+
+  @Test
+  public void nullAccountId() throws Exception {
+    PushOneCommit.Result r = createChange();
+    PatchSet.Id psId = r.getPatchSetId();
+    Change.Id id = psId.getParentKey();
+
+    // Events need to be otherwise identical for the account ID to be compared.
+    ChangeMessage msg1 =
+        insertMessage(id, psId, user.getId(), TimeUtil.nowTs(), "message 1");
+    insertMessage(id, psId, null, msg1.getWrittenOn(), "message 2");
+
+    checker.rebuildAndCheckChanges(id);
+  }
+
+  @Test
+  public void nullPatchSetId() throws Exception {
+    PushOneCommit.Result r = createChange();
+    PatchSet.Id psId1 = r.getPatchSetId();
+    Change.Id id = psId1.getParentKey();
+
+    // Events need to be otherwise identical for the PatchSet.ID to be compared.
+    ChangeMessage msg1 =
+        insertMessage(id, null, user.getId(), TimeUtil.nowTs(), "message 1");
+    insertMessage(id, null, user.getId(), msg1.getWrittenOn(), "message 2");
+
+    PatchSet.Id psId2 = amendChange(r.getChangeId()).getPatchSetId();
+
+    ChangeMessage msg3 =
+        insertMessage(id, null, user.getId(), TimeUtil.nowTs(), "message 3");
+    insertMessage(id, null, user.getId(), msg3.getWrittenOn(), "message 4");
+
+    checker.rebuildAndCheckChanges(id);
+
+    notesMigration.setWriteChanges(true);
+    notesMigration.setReadChanges(true);
+
+    ChangeNotes notes = notesFactory.create(db, project, id);
+    Map<String, PatchSet.Id> psIds = new HashMap<>();
+    for (ChangeMessage msg : notes.getChangeMessages()) {
+      PatchSet.Id psId = msg.getPatchSetId();
+      assertThat(psId).named("patchset for " + msg).isNotNull();
+      psIds.put(msg.getMessage(), psId);
+    }
+    // Patch set IDs were replaced during conversion process.
+    assertThat(psIds).containsEntry("message 1", psId1);
+    assertThat(psIds).containsEntry("message 2", psId1);
+    assertThat(psIds).containsEntry("message 3", psId2);
+    assertThat(psIds).containsEntry("message 4", psId2);
+  }
+
+  @Test
   public void noWriteToNewRef() throws Exception {
     PushOneCommit.Result r = createChange();
     Change.Id id = r.getPatchSetId().getParentKey();
@@ -256,7 +371,7 @@
 
   private void assertChangeUpToDate(boolean expected, Change.Id id)
       throws Exception {
-    try (Repository repo = repoManager.openMetadataRepository(project)) {
+    try (Repository repo = repoManager.openRepository(project)) {
       Change c = unwrapDb().changes().get(id);
       assertThat(c).isNotNull();
       assertThat(c.getNoteDbState()).isNotNull();
@@ -267,7 +382,7 @@
 
   private void assertDraftsUpToDate(boolean expected, Change.Id changeId,
       TestAccount account) throws Exception {
-    try (Repository repo = repoManager.openMetadataRepository(allUsers)) {
+    try (Repository repo = repoManager.openRepository(allUsers)) {
       Change c = unwrapDb().changes().get(changeId);
       assertThat(c).isNotNull();
       assertThat(c.getNoteDbState()).isNotNull();
@@ -278,7 +393,7 @@
   }
 
   private ObjectId getMetaRef(Project.NameKey p, String name) throws Exception {
-    try (Repository repo = repoManager.openMetadataRepository(p)) {
+    try (Repository repo = repoManager.openRepository(p)) {
       Ref ref = repo.exactRef(name);
       return ref != null ? ref.getObjectId() : null;
     }
@@ -298,6 +413,52 @@
     }
   }
 
+  private void putComment(TestAccount account, Change.Id id, int line, String msg)
+      throws Exception {
+    CommentInput in = new CommentInput();
+    in.line = line;
+    in.message = msg;
+    ReviewInput rin = new ReviewInput();
+    rin.comments = new HashMap<>();
+    rin.comments.put(PushOneCommit.FILE_NAME, ImmutableList.of(in));
+    rin.drafts = ReviewInput.DraftHandling.KEEP;
+    AcceptanceTestRequestScope.Context old = setApiUser(account);
+    try {
+      gApi.changes().id(id.get()).current().review(rin);
+    } finally {
+      atrScope.set(old);
+    }
+  }
+
+  private void publishDrafts(TestAccount account, Change.Id id)
+      throws Exception {
+    ReviewInput rin = new ReviewInput();
+    rin.drafts = ReviewInput.DraftHandling.PUBLISH_ALL_REVISIONS;
+    AcceptanceTestRequestScope.Context old = setApiUser(account);
+    try {
+      gApi.changes().id(id.get()).current().review(rin);
+    } finally {
+      atrScope.set(old);
+    }
+  }
+
+  private ChangeMessage insertMessage(Change.Id id, PatchSet.Id psId,
+      Account.Id author, Timestamp ts, String message) throws Exception {
+    ChangeMessage msg = new ChangeMessage(
+        new ChangeMessage.Key(id, ChangeUtil.messageUUID(db)),
+        author, ts, psId);
+    msg.setMessage(message);
+    db.changeMessages().insert(Collections.singleton(msg));
+
+    Change c = db.changes().get(id);
+    if (ts.compareTo(c.getLastUpdatedOn()) > 0) {
+      c.setLastUpdatedOn(ts);
+      db.changes().update(Collections.singleton(c));
+    }
+
+    return msg;
+  }
+
   private ReviewDb unwrapDb() {
     ReviewDb db = dbProvider.get();
     if (db instanceof DisabledChangesReviewDbWrapper) {
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/LabelTypeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/LabelTypeIT.java
index a22b09d..a69bb19 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/LabelTypeIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/LabelTypeIT.java
@@ -26,7 +26,6 @@
 import com.google.gerrit.extensions.common.ChangeInfo;
 import com.google.gerrit.extensions.common.LabelInfo;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
-import com.google.gerrit.server.git.MetaDataUpdate;
 import com.google.gerrit.server.git.ProjectConfig;
 import com.google.gerrit.server.project.Util;
 
@@ -416,12 +415,6 @@
     saveProjectConfig(cfg);
   }
 
-  private void saveProjectConfig(ProjectConfig cfg) throws Exception {
-    try (MetaDataUpdate md = metaDataUpdateFactory.create(project)) {
-      cfg.commit(md);
-    }
-  }
-
   @Override
   protected void merge(PushOneCommit.Result r) throws Exception {
     super.merge(r);
diff --git a/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java b/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java
index 289c8cc..726a5f1 100644
--- a/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java
+++ b/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java
@@ -490,7 +490,7 @@
 
     private void touch(SqlHandle c, K key) throws SQLException {
       if (c.touch == null) {
-        c.touch =c.conn.prepareStatement("UPDATE data SET accessed=? WHERE k=?");
+        c.touch = c.conn.prepareStatement("UPDATE data SET accessed=? WHERE k=?");
       }
       try {
         c.touch.setTimestamp(1, TimeUtil.nowTs());
diff --git a/gerrit-common/BUCK b/gerrit-common/BUCK
index df6237c..ac2045e 100644
--- a/gerrit-common/BUCK
+++ b/gerrit-common/BUCK
@@ -6,16 +6,6 @@
   SRC + 'common/auth/SignInRequired.java',
 ]
 
-EXCLUDES = [
-  SRC + 'common/SiteLibraryLoaderUtil.java',
-  SRC + 'common/PluginData.java',
-  SRC + 'common/FileUtil.java',
-  SRC + 'common/IoUtil.java',
-  SRC + 'common/RawInputUtil.java',
-  SRC + 'common/TimeUtil.java',
-  SRC + 'common/data/SubscribeSection.java',
-]
-
 java_library(
   name = 'annotations',
   srcs = ANNOTATIONS,
@@ -24,13 +14,18 @@
 
 gwt_module(
   name = 'client',
-  srcs = glob([SRC + 'common/**/*.java'], excludes = EXCLUDES),
+  srcs = glob([SRC + 'common/**/*.java']),
   gwt_xml = SRC + 'Common.gwt.xml',
   exported_deps = [
-    '//gerrit-extension-api:client',
+    '//gerrit-extension-api:api',
     '//gerrit-prettify:client',
+    '//lib:guava',
     '//lib:gwtorm_client',
+    '//lib/joda:joda-time',
+    '//lib/log:api',
+    '@jgit//org.eclipse.jgit:jgit',
   ],
+  provided_deps = ['//lib:servlet-api-3_1'],
   visibility = ['PUBLIC'],
 )
 
@@ -43,9 +38,9 @@
     '//gerrit-patch-jgit:server',
     '//gerrit-prettify:server',
     '//gerrit-reviewdb:server',
+    '//lib:guava',
     '//lib:gwtjsonrpc',
     '//lib:gwtorm',
-    '//lib:guava',
     '//lib/joda:joda-time',
     '//lib/log:api',
     '@jgit//org.eclipse.jgit:jgit',
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/FileUtil.java b/gerrit-common/src/main/java/com/google/gerrit/common/FileUtil.java
index ed28ec0..83dc4d8 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/FileUtil.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/FileUtil.java
@@ -14,6 +14,8 @@
 
 package com.google.gerrit.common;
 
+import com.google.common.annotations.GwtIncompatible;
+
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.storage.file.FileBasedConfig;
 import org.eclipse.jgit.util.IO;
@@ -25,6 +27,7 @@
 import java.nio.file.Path;
 import java.util.Arrays;
 
+@GwtIncompatible("Unemulated classes in java.io, java.nio and JGit")
 public class FileUtil {
   public static boolean modified(FileBasedConfig cfg) throws IOException {
     byte[] curVers;
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 9bc2ea5..3422a78 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
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.common;
 
+import com.google.common.annotations.GwtIncompatible;
 import com.google.common.collect.Sets;
 
 import java.io.IOException;
@@ -29,6 +30,7 @@
 import java.util.Collections;
 import java.util.Set;
 
+@GwtIncompatible("Unemulated methods in Class and OutputStream")
 public final class IoUtil {
   public static void copyWithThread(final InputStream src,
       final OutputStream dst) {
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/PluginData.java b/gerrit-common/src/main/java/com/google/gerrit/common/PluginData.java
index 27dc639..4645158 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/PluginData.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/PluginData.java
@@ -14,9 +14,12 @@
 
 package com.google.gerrit.common;
 
+import com.google.common.annotations.GwtIncompatible;
+
 import java.nio.file.Path;
 import java.util.Objects;
 
+@GwtIncompatible("Unemulated java.nio.file.Path")
 public class PluginData {
   public final String name;
   public final String version;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/RawInputUtil.java b/gerrit-common/src/main/java/com/google/gerrit/common/RawInputUtil.java
index dfd8453..edcd111 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/RawInputUtil.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/RawInputUtil.java
@@ -16,6 +16,7 @@
 
 import static java.nio.charset.StandardCharsets.UTF_8;
 
+import com.google.common.annotations.GwtIncompatible;
 import com.google.common.base.Preconditions;
 import com.google.gerrit.extensions.restapi.RawInput;
 
@@ -25,6 +26,7 @@
 
 import javax.servlet.http.HttpServletRequest;
 
+@GwtIncompatible("Unemulated classes in java.io and javax.servlet")
 public class RawInputUtil {
   public static RawInput create(String content) {
     return create(content.getBytes(UTF_8));
@@ -52,7 +54,7 @@
   }
 
   public static RawInput create(final byte[] bytes) {
-    return create (bytes, "application/octet-stream");
+    return create(bytes, "application/octet-stream");
   }
 
   public static RawInput create(final HttpServletRequest req) {
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/SiteLibraryLoaderUtil.java b/gerrit-common/src/main/java/com/google/gerrit/common/SiteLibraryLoaderUtil.java
index 2511a51..bf87d7b 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/SiteLibraryLoaderUtil.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/SiteLibraryLoaderUtil.java
@@ -16,6 +16,7 @@
 
 import static com.google.gerrit.common.FileUtil.lastModified;
 
+import com.google.common.annotations.GwtIncompatible;
 import com.google.common.collect.ComparisonChain;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Ordering;
@@ -30,6 +31,7 @@
 import java.nio.file.Path;
 import java.util.List;
 
+@GwtIncompatible("Unemulated classes in java.nio and Guava")
 public final class SiteLibraryLoaderUtil {
   private static final Logger log =
       LoggerFactory.getLogger(SiteLibraryLoaderUtil.class);
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/TimeUtil.java b/gerrit-common/src/main/java/com/google/gerrit/common/TimeUtil.java
index 4274b5a..ec91a81 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/TimeUtil.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/TimeUtil.java
@@ -14,11 +14,14 @@
 
 package com.google.gerrit.common;
 
+import com.google.common.annotations.GwtIncompatible;
+
 import org.joda.time.DateTimeUtils;
 
 import java.sql.Timestamp;
 
 /** Static utility methods for dealing with dates and times. */
+@GwtIncompatible("Unemulated org.joda.time.DateTimeUtils")
 public class TimeUtil {
   public static long nowMs() {
     return DateTimeUtils.currentTimeMillis();
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeDetailService.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeDetailService.java
deleted file mode 100644
index 6d9c2cd..0000000
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeDetailService.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (C) 2008 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.common.data;
-
-import com.google.gerrit.common.audit.Audit;
-import com.google.gerrit.extensions.client.DiffPreferencesInfo;
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gwtjsonrpc.common.AsyncCallback;
-import com.google.gwtjsonrpc.common.RemoteJsonService;
-import com.google.gwtjsonrpc.common.RpcImpl;
-import com.google.gwtjsonrpc.common.RpcImpl.Version;
-
-@RpcImpl(version = Version.V2_0)
-public interface ChangeDetailService extends RemoteJsonService {
-  @Audit
-  void patchSetDetail(PatchSet.Id key, AsyncCallback<PatchSetDetail> callback);
-
-  @Audit
-  void patchSetDetail2(PatchSet.Id baseId, PatchSet.Id key,
-      DiffPreferencesInfo diffPrefs, AsyncCallback<PatchSetDetail> callback);
-}
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/GarbageCollectionResult.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/GarbageCollectionResult.java
index a052f4f..0156b7d 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/GarbageCollectionResult.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/GarbageCollectionResult.java
@@ -39,7 +39,7 @@
   }
 
   public static class Error {
-    public static enum Type {
+    public enum Type {
       /** Git garbage collection was already scheduled for this project */
       GC_ALREADY_SCHEDULED,
 
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchDetailService.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchDetailService.java
deleted file mode 100644
index d9601f0..0000000
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchDetailService.java
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (C) 2008 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.common.data;
-
-import com.google.gerrit.common.audit.Audit;
-import com.google.gerrit.extensions.client.DiffPreferencesInfo;
-import com.google.gerrit.reviewdb.client.Patch;
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gwtjsonrpc.common.AsyncCallback;
-import com.google.gwtjsonrpc.common.RemoteJsonService;
-import com.google.gwtjsonrpc.common.RpcImpl;
-import com.google.gwtjsonrpc.common.RpcImpl.Version;
-
-@RpcImpl(version = Version.V2_0)
-public interface PatchDetailService extends RemoteJsonService {
-  @Audit
-  void patchScript(Patch.Key key, PatchSet.Id a, PatchSet.Id b,
-      DiffPreferencesInfo diffPrefs, AsyncCallback<PatchScript> callback);
-}
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchScript.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchScript.java
index f23afb1..5167fe6 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchScript.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchScript.java
@@ -27,11 +27,11 @@
 import java.util.List;
 
 public class PatchScript {
-  public static enum DisplayMethod {
+  public enum DisplayMethod {
     NONE, DIFF, IMG
   }
 
-  public static enum FileMode {
+  public enum FileMode {
     FILE, SYMLINK, GITLINK
   }
 
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchSetDetail.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchSetDetail.java
deleted file mode 100644
index 39f5cb0..0000000
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchSetDetail.java
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright (C) 2008 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.common.data;
-
-import com.google.gerrit.reviewdb.client.Patch;
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gerrit.reviewdb.client.PatchSetInfo;
-import com.google.gerrit.reviewdb.client.Project;
-
-import java.util.List;
-
-public class PatchSetDetail {
-  protected PatchSet patchSet;
-  protected PatchSetInfo info;
-  protected List<Patch> patches;
-  protected Project.NameKey project;
-
-  public PatchSetDetail() {
-  }
-
-  public PatchSet getPatchSet() {
-    return patchSet;
-  }
-
-  public void setPatchSet(final PatchSet ps) {
-    patchSet = ps;
-  }
-
-  public PatchSetInfo getInfo() {
-    return info;
-  }
-
-  public void setInfo(final PatchSetInfo i) {
-    info = i;
-  }
-
-  public List<Patch> getPatches() {
-    return patches;
-  }
-
-  public void setPatches(final List<Patch> p) {
-    patches = p;
-  }
-
-  public Project.NameKey getProject() {
-    return project;
-  }
-
-  public void setProject(final Project.NameKey p) {
-    project = p;
-  }
-}
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/PermissionRule.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/PermissionRule.java
index 5aeb797..c1289f5 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/PermissionRule.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/PermissionRule.java
@@ -17,7 +17,7 @@
 public class PermissionRule implements Comparable<PermissionRule> {
   public static final String FORCE_PUSH = "Force Push";
   public static final String FORCE_EDIT = "Force Edit";
-  public static enum Action {
+  public enum Action {
     ALLOW, DENY, BLOCK,
 
     INTERACTIVE, BATCH
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/SubmitRecord.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/SubmitRecord.java
index 5a32fcf..9dccf0c 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/SubmitRecord.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/SubmitRecord.java
@@ -23,7 +23,7 @@
  * Describes the state required to submit a change.
  */
 public class SubmitRecord {
-  public static enum Status {
+  public enum Status {
     /** The change is ready for submission. */
     OK,
 
@@ -49,7 +49,7 @@
   public String errorMessage;
 
   public static class Label {
-    public static enum Status {
+    public enum Status {
       /**
        * This label provides what is necessary for submission.
        * <p>
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/SubmitTypeRecord.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/SubmitTypeRecord.java
index cd226ef..b6ce797 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/SubmitTypeRecord.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/SubmitTypeRecord.java
@@ -20,7 +20,7 @@
  * Describes the submit type for a change.
  */
 public class SubmitTypeRecord {
-  public static enum Status {
+  public enum Status {
     /** The type was computed successfully */
     OK,
 
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/SubscribeSection.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/SubscribeSection.java
index 7ec1eda..b05f335 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/SubscribeSection.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/SubscribeSection.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.common.data;
 
+import com.google.common.annotations.GwtIncompatible;
 import com.google.gerrit.reviewdb.client.Branch;
 import com.google.gerrit.reviewdb.client.Project;
 
@@ -25,6 +26,7 @@
 import java.util.List;
 
 /** Portion of a {@link Project} describing superproject subscription rules. */
+@GwtIncompatible("Unemulated org.eclipse.jgit.transport.RefSpec")
 public class SubscribeSection {
 
   private final List<RefSpec> refSpecs;
diff --git a/gerrit-extension-api/BUCK b/gerrit-extension-api/BUCK
index 307aefa..67bfdc1 100644
--- a/gerrit-extension-api/BUCK
+++ b/gerrit-extension-api/BUCK
@@ -70,7 +70,8 @@
   srcs = SRCS,
   deps = [
     '//lib/guice:javax-inject',
-    '//lib/guice:guice_library'
+    '//lib/guice:guice_library',
+    '//lib/guice:guice-assistedinject',
   ],
   visibility = ['PUBLIC'],
 )
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/GerritApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/GerritApi.java
index 4404f94..c2e3787 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/GerritApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/GerritApi.java
@@ -32,7 +32,7 @@
    * A default implementation which allows source compatibility
    * when adding new methods to the interface.
    **/
-  public class NotImplemented implements GerritApi {
+  class NotImplemented implements GerritApi {
     @Override
     public Accounts accounts() {
       throw new NotImplementedException();
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/AccountApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/AccountApi.java
index 23aae5d..a45d8d3 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/AccountApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/AccountApi.java
@@ -19,6 +19,7 @@
 import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
 import com.google.gerrit.extensions.common.AccountInfo;
 import com.google.gerrit.extensions.common.GpgKeyInfo;
+import com.google.gerrit.extensions.common.SshKeyInfo;
 import com.google.gerrit.extensions.restapi.NotImplementedException;
 import com.google.gerrit.extensions.restapi.RestApiException;
 
@@ -46,6 +47,9 @@
   void unstarChange(String id) throws RestApiException;
   void addEmail(EmailInput input) throws RestApiException;
 
+  List<SshKeyInfo> listSshKeys() throws RestApiException;
+  SshKeyInfo addSshKey(String key) throws RestApiException;
+
   Map<String, GpgKeyInfo> listGpgKeys() throws RestApiException;
   Map<String, GpgKeyInfo> putGpgKeys(List<String> add, List<String> remove)
       throws RestApiException;
@@ -55,7 +59,7 @@
    * A default implementation which allows source compatibility
    * when adding new methods to the interface.
    **/
-  public class NotImplemented implements AccountApi {
+  class NotImplemented implements AccountApi {
     @Override
     public AccountInfo get() throws RestApiException {
       throw new NotImplementedException();
@@ -115,6 +119,16 @@
     }
 
     @Override
+    public List<SshKeyInfo> listSshKeys() throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public SshKeyInfo addSshKey(String key) throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
     public Map<String, GpgKeyInfo> putGpgKeys(List<String> add,
         List<String> remove) throws RestApiException {
       throw new NotImplementedException();
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/Accounts.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/Accounts.java
index 9cddda9..0d2e025 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/Accounts.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/Accounts.java
@@ -75,7 +75,7 @@
    *
    * @see #suggestAccounts()
    */
-  public abstract class SuggestAccountsRequest {
+  abstract class SuggestAccountsRequest {
     private String query;
     private int limit;
 
@@ -116,7 +116,7 @@
    * A default implementation which allows source compatibility
    * when adding new methods to the interface.
    **/
-  public class NotImplemented implements Accounts {
+  class NotImplemented implements Accounts {
     @Override
     public AccountApi id(String id) throws RestApiException {
       throw new NotImplementedException();
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/GpgKeyApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/GpgKeyApi.java
index ffdcf87..6f87e8b 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/GpgKeyApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/GpgKeyApi.java
@@ -26,7 +26,7 @@
    * A default implementation which allows source compatibility
    * when adding new methods to the interface.
    */
-  public class NotImplemented implements GpgKeyApi {
+  class NotImplemented implements GpgKeyApi {
     @Override
     public GpgKeyInfo get() throws RestApiException {
       throw new NotImplementedException();
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
index ae5f0b8..3a64645 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
@@ -157,7 +157,7 @@
   ChangeInfo check() throws RestApiException;
   ChangeInfo check(FixInput fix) throws RestApiException;
 
-  public abstract class SuggestedReviewersRequest {
+  abstract class SuggestedReviewersRequest {
     private String query;
     private int limit;
 
@@ -186,7 +186,7 @@
    * A default implementation which allows source compatibility
    * when adding new methods to the interface.
    **/
-  public class NotImplemented implements ChangeApi {
+  class NotImplemented implements ChangeApi {
     @Override
     public String id() {
       throw new NotImplementedException();
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/Changes.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/Changes.java
index b1381e7..aa67473 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/Changes.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/Changes.java
@@ -64,7 +64,7 @@
   QueryRequest query();
   QueryRequest query(String query);
 
-  public abstract class QueryRequest {
+  abstract class QueryRequest {
     private String query;
     private int limit;
     private int start;
@@ -140,7 +140,7 @@
    * A default implementation which allows source compatibility
    * when adding new methods to the interface.
    **/
-  public class NotImplemented implements Changes {
+  class NotImplemented implements Changes {
     @Override
     public ChangeApi id(int id) throws RestApiException {
       throw new NotImplementedException();
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/CommentApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/CommentApi.java
index d0c5633..adac284 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/CommentApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/CommentApi.java
@@ -25,7 +25,7 @@
    * A default implementation which allows source compatibility
    * when adding new methods to the interface.
    **/
-  public class NotImplemented implements CommentApi {
+  class NotImplemented implements CommentApi {
     @Override
     public CommentInfo get() throws RestApiException {
       throw new NotImplementedException();
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/DraftApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/DraftApi.java
index 80a71f8..50335db 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/DraftApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/DraftApi.java
@@ -26,7 +26,7 @@
    * A default implementation which allows source compatibility
    * when adding new methods to the interface.
    **/
-  public class NotImplemented extends CommentApi.NotImplemented
+  class NotImplemented extends CommentApi.NotImplemented
       implements DraftApi {
     @Override
     public CommentInfo update(DraftInput in) throws RestApiException {
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/FileApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/FileApi.java
index 5e995e2..3641ac5 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/FileApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/FileApi.java
@@ -40,7 +40,7 @@
    */
   DiffRequest diffRequest() throws RestApiException;
 
-  public abstract class DiffRequest {
+  abstract class DiffRequest {
     private String base;
     private Integer context;
     private Boolean intraline;
@@ -89,7 +89,7 @@
    * A default implementation which allows source compatibility
    * when adding new methods to the interface.
    **/
-  public class NotImplemented implements FileApi {
+  class NotImplemented implements FileApi {
     @Override
     public BinaryResult content() throws RestApiException {
       throw new NotImplementedException();
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ReviewInput.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ReviewInput.java
index e6ce6b2..c1610c3 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ReviewInput.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ReviewInput.java
@@ -26,6 +26,8 @@
   @DefaultInput
   public String message;
 
+  public String tag;
+
   public Map<String, Short> labels;
   public Map<String, List<CommentInput>> comments;
 
@@ -66,7 +68,7 @@
    */
   public String onBehalfOf;
 
-  public static enum DraftHandling {
+  public enum DraftHandling {
     /** Delete pending drafts on this revision only. */
     DELETE,
 
@@ -80,7 +82,7 @@
     PUBLISH_ALL_REVISIONS
   }
 
-  public static enum NotifyHandling {
+  public enum NotifyHandling {
     NONE, OWNER, OWNER_REVIEWERS, ALL
   }
 
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
index 627917c..b23c7f9 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
@@ -75,7 +75,7 @@
    * A default implementation which allows source compatibility
    * when adding new methods to the interface.
    **/
-  public class NotImplemented implements RevisionApi {
+  class NotImplemented implements RevisionApi {
     @Override
     public void delete() throws RestApiException {
       throw new NotImplementedException();
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/SubmitInput.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/SubmitInput.java
index 053248f..6abf83df 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/SubmitInput.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/SubmitInput.java
@@ -14,10 +14,14 @@
 
 package com.google.gerrit.extensions.api.changes;
 
+import com.google.gerrit.extensions.api.changes.ReviewInput.NotifyHandling;
+
 public class SubmitInput {
   /** Not used anymore, kept for backward compatibility */
   @Deprecated
   public boolean waitForMerge;
 
   public String onBehalfOf;
+
+  public NotifyHandling notify = NotifyHandling.ALL;
 }
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/config/Config.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/config/Config.java
index 348cf4b..3f4971e 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/config/Config.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/config/Config.java
@@ -26,7 +26,7 @@
    * A default implementation which allows source compatibility
    * when adding new methods to the interface.
    **/
-  public class NotImplemented implements Config {
+  class NotImplemented implements Config {
     @Override
     public Server server() {
       throw new NotImplementedException();
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/config/Server.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/config/Server.java
index c093b18..1c535dd 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/config/Server.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/config/Server.java
@@ -27,7 +27,7 @@
    * A default implementation which allows source compatibility
    * when adding new methods to the interface.
    **/
-  public class NotImplemented implements Server {
+  class NotImplemented implements Server {
     @Override
     public String getVersion() throws RestApiException {
       throw new NotImplementedException();
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/groups/Groups.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/groups/Groups.java
index b909f31..6b4f5f3 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/groups/Groups.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/groups/Groups.java
@@ -51,7 +51,7 @@
   /** @return new request for listing groups. */
   ListRequest list();
 
-  public abstract class ListRequest {
+  abstract class ListRequest {
     private final EnumSet<ListGroupsOption> options =
         EnumSet.noneOf(ListGroupsOption.class);
     private final List<String> projects = new ArrayList<>();
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/BranchApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/BranchApi.java
index e7c98e9..222248d 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/BranchApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/BranchApi.java
@@ -34,7 +34,7 @@
    * A default implementation which allows source compatibility
    * when adding new methods to the interface.
    **/
-  public class NotImplemented implements BranchApi {
+  class NotImplemented implements BranchApi {
     @Override
     public BranchApi create(BranchInput in) throws RestApiException {
       throw new NotImplementedException();
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ChildProjectApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ChildProjectApi.java
index a930f0d..3bffac0 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ChildProjectApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ChildProjectApi.java
@@ -26,7 +26,7 @@
    * A default implementation which allows source compatibility
    * when adding new methods to the interface.
    **/
-  public class NotImplemented implements ChildProjectApi {
+  class NotImplemented implements ChildProjectApi {
     @Override
     public ProjectInfo get() throws RestApiException {
       throw new NotImplementedException();
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectApi.java
index e3eb4be..16efdd1 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectApi.java
@@ -31,7 +31,7 @@
   ListRefsRequest<BranchInfo> branches();
   ListRefsRequest<TagInfo> tags();
 
-  public abstract class ListRefsRequest<T extends RefInfo> {
+  abstract class ListRefsRequest<T extends RefInfo> {
     protected int limit;
     protected int start;
     protected String substring;
@@ -108,7 +108,7 @@
    * A default implementation which allows source compatibility
    * when adding new methods to the interface.
    **/
-  public class NotImplemented implements ProjectApi {
+  class NotImplemented implements ProjectApi {
     @Override
     public ProjectApi create() throws RestApiException {
       throw new NotImplementedException();
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/Projects.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/Projects.java
index 0e848b9..fdbadb2 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/Projects.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/Projects.java
@@ -60,8 +60,8 @@
 
   ListRequest list();
 
-  public abstract class ListRequest {
-    public static enum FilterType {
+  abstract class ListRequest {
+    public enum FilterType {
       CODE, PARENT_CANDIDATES, PERMISSIONS, ALL
     }
 
@@ -175,7 +175,7 @@
    * A default implementation which allows source compatibility
    * when adding new methods to the interface.
    **/
-  public class NotImplemented implements Projects {
+  class NotImplemented implements Projects {
     @Override
     public ProjectApi name(String name) throws RestApiException {
       throw new NotImplementedException();
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/TagApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/TagApi.java
index 6cc1ba4..3071fd2 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/TagApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/TagApi.java
@@ -24,7 +24,7 @@
    * A default implementation which allows source compatibility
    * when adding new methods to the interface.
    **/
-  public class NotImplemented implements TagApi {
+  class NotImplemented implements TagApi {
     @Override
     public TagInfo get() throws RestApiException {
       throw new NotImplementedException();
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/DiffPreferencesInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/DiffPreferencesInfo.java
index 703f7b3..1373b09 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/DiffPreferencesInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/DiffPreferencesInfo.java
@@ -32,7 +32,7 @@
   public static final short[] CONTEXT_CHOICES =
       {3, 10, 25, 50, 75, 100, WHOLE_FILE_CONTEXT};
 
-  public static enum Whitespace {
+  public enum Whitespace {
     IGNORE_NONE,
     IGNORE_TRAILING,
     IGNORE_LEADING_AND_TRAILING,
@@ -60,6 +60,7 @@
   public Whitespace ignoreWhitespace;
   public Boolean retainHeader;
   public Boolean skipDeleted;
+  public Boolean skipUnchanged;
   public Boolean skipUncommented;
 
   public static DiffPreferencesInfo defaults() {
@@ -78,6 +79,7 @@
     i.showTabs = true;
     i.showWhitespaceErrors = true;
     i.skipDeleted = false;
+    i.skipUnchanged = false;
     i.skipUncommented = false;
     i.syntaxHighlighting = true;
     i.hideTopMenu = false;
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/EditPreferencesInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/EditPreferencesInfo.java
index 3e45523..ab11612 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/EditPreferencesInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/EditPreferencesInfo.java
@@ -18,6 +18,7 @@
 public class EditPreferencesInfo {
   public Integer tabSize;
   public Integer lineLength;
+  public Integer indentUnit;
   public Integer cursorBlinkRate;
   public Boolean hideTopMenu;
   public Boolean showTabs;
@@ -33,6 +34,7 @@
     EditPreferencesInfo i = new EditPreferencesInfo();
     i.tabSize = 8;
     i.lineLength = 100;
+    i.indentUnit = 2;
     i.cursorBlinkRate = 0;
     i.hideTopMenu = false;
     i.showTabs = true;
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/GeneralPreferencesInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/GeneralPreferencesInfo.java
index cb3ab59..9754f12 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/GeneralPreferencesInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/GeneralPreferencesInfo.java
@@ -27,11 +27,11 @@
   public static final int[] PAGESIZE_CHOICES = {10, 25, 50, 100};
 
   /** Preferred method to download a change. */
-  public static enum DownloadCommand {
+  public enum DownloadCommand {
     REPO_DOWNLOAD, PULL, CHECKOUT, CHERRY_PICK, FORMAT_PATCH
   }
 
-  public static enum DateFormat {
+  public enum DateFormat {
     /** US style dates: Apr 27, Feb 14, 2010 */
     STD("MMM d", "MMM d, yyyy"),
 
@@ -64,7 +64,7 @@
     }
   }
 
-  public static enum ReviewCategoryStrategy {
+  public enum ReviewCategoryStrategy {
     NONE,
     NAME,
     EMAIL,
@@ -72,18 +72,18 @@
     ABBREV
   }
 
-  public static enum DiffView {
+  public enum DiffView {
     SIDE_BY_SIDE,
     UNIFIED_DIFF
   }
 
-  public static enum EmailStrategy {
+  public enum EmailStrategy {
     ENABLED,
     CC_ON_OWN_COMMENTS,
     DISABLED
   }
 
-  public static enum TimeFormat {
+  public enum TimeFormat {
     /** 12-hour clock: 1:15 am, 2:13 pm */
     HHMM_12("h:mm a"),
 
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/GerritTopMenu.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/GerritTopMenu.java
index 81d6149..0a5b033 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/GerritTopMenu.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/GerritTopMenu.java
@@ -15,11 +15,11 @@
 package com.google.gerrit.extensions.client;
 
 public enum GerritTopMenu {
-  ALL, MY, DIFFERENCES, PROJECTS, PEOPLE, PLUGINS, DOCUMENTATION;
+  ALL, MY, PROJECTS, PEOPLE, PLUGINS, DOCUMENTATION;
 
   public final String menuName;
 
-  private GerritTopMenu() {
+  GerritTopMenu() {
     menuName = name().substring(0, 1) + name().substring(1).toLowerCase();
   }
 }
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/KeyMapType.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/KeyMapType.java
index 261168d..66641b0 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/KeyMapType.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/KeyMapType.java
@@ -17,5 +17,6 @@
 public enum KeyMapType {
   DEFAULT,
   EMACS,
+  SUBLIME,
   VIM
 }
\ No newline at end of file
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/ListChangesOption.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/ListChangesOption.java
index 4c336f7..88c02b82 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/ListChangesOption.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/ListChangesOption.java
@@ -70,7 +70,7 @@
 
   private final int value;
 
-  private ListChangesOption(int v) {
+  ListChangesOption(int v) {
     this.value = v;
   }
 
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/ListGroupsOption.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/ListGroupsOption.java
index d87f73e..e95570f 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/ListGroupsOption.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/ListGroupsOption.java
@@ -26,7 +26,7 @@
 
   private final int value;
 
-  private ListGroupsOption(int v) {
+  ListGroupsOption(int v) {
     this.value = v;
   }
 
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ApprovalInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ApprovalInfo.java
index ce120cd..6d28dbc 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ApprovalInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ApprovalInfo.java
@@ -17,6 +17,7 @@
 import java.sql.Timestamp;
 
 public class ApprovalInfo extends AccountInfo {
+  public String tag;
   public Integer value;
   public Timestamp date;
 
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ChangeMessageInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ChangeMessageInfo.java
index 7ad40b5..e79918f 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ChangeMessageInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ChangeMessageInfo.java
@@ -18,6 +18,7 @@
 
 public class ChangeMessageInfo {
   public String id;
+  public String tag;
   public AccountInfo author;
   public Timestamp date;
   public String message;
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/CommentInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/CommentInfo.java
index b1f8183..b7535e1 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/CommentInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/CommentInfo.java
@@ -18,4 +18,5 @@
 
 public class CommentInfo extends Comment {
   public AccountInfo author;
+  public String tag;
 }
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/DiffInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/DiffInfo.java
index 58b2d39..3df4b86 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/DiffInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/DiffInfo.java
@@ -35,7 +35,7 @@
   // Binary file
   public Boolean binary;
 
-  public static enum IntraLineStatus {
+  public enum IntraLineStatus {
     OK,
     TIMEOUT,
     FAILURE
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ProblemInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ProblemInfo.java
index d04b346..4dd910d 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ProblemInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ProblemInfo.java
@@ -15,7 +15,7 @@
 package com.google.gerrit.extensions.common;
 
 public class ProblemInfo {
-  public static enum Status {
+  public enum Status {
     FIXED, FIX_FAILED
   }
 
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/BinaryResult.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/BinaryResult.java
index a21c2d4..068d9a0 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/BinaryResult.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/BinaryResult.java
@@ -62,7 +62,7 @@
   private Charset characterEncoding;
   private long contentLength = -1;
   private boolean gzip = true;
-  private boolean base64 = false;
+  private boolean base64;
   private String attachmentName;
 
   /** @return the MIME type of the result, for HTTP clients. */
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/systemstatus/ServerInformation.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/systemstatus/ServerInformation.java
index c7deedb..45aec57 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/systemstatus/ServerInformation.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/systemstatus/ServerInformation.java
@@ -17,7 +17,7 @@
 /** Exports current server information to an extension. */
 public interface ServerInformation {
   /** Current state of the server. */
-  public enum State {
+  enum State {
     /**
      * The server is starting up, and network connections are not yet being
      * accepted. Plugins or extensions starting during this time are starting
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/PatchSetWebLink.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/PatchSetWebLink.java
index ad74849..b9004f2 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/PatchSetWebLink.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/PatchSetWebLink.java
@@ -18,7 +18,7 @@
 import com.google.gerrit.extensions.common.WebLinkInfo;
 
 @ExtensionPoint
-public interface PatchSetWebLink extends WebLink{
+public interface PatchSetWebLink extends WebLink {
 
   /**
    * {@link com.google.gerrit.extensions.common.WebLinkInfo}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/TopMenu.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/TopMenu.java
index bc41813..7ad12cd 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/TopMenu.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/TopMenu.java
@@ -22,7 +22,7 @@
 
 @ExtensionPoint
 public interface TopMenu {
-  public class MenuEntry {
+  class MenuEntry {
     public final String name;
     public final List<MenuItem> items;
 
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/UiAction.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/UiAction.java
index fb81e0c..1807673 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/UiAction.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/UiAction.java
@@ -32,7 +32,7 @@
   Description getDescription(R resource);
 
   /** Describes an action invokable through the web interface. */
-  public static class Description {
+  class Description {
     private String method;
     private String id;
     private String label;
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/WebLink.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/WebLink.java
index e497f7d..fd677ca 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/WebLink.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/WebLink.java
@@ -24,7 +24,7 @@
   /**
    * Class that holds target defaults for WebLink anchors.
    */
-  public static class Target {
+  class Target {
     /**
      * Opens the link in a new window or tab
      */
diff --git a/gerrit-gpg/src/main/java/com/google/gerrit/gpg/server/PostGpgKeys.java b/gerrit-gpg/src/main/java/com/google/gerrit/gpg/server/PostGpgKeys.java
index d3ca8c1..7e55d45 100644
--- a/gerrit-gpg/src/main/java/com/google/gerrit/gpg/server/PostGpgKeys.java
+++ b/gerrit-gpg/src/main/java/com/google/gerrit/gpg/server/PostGpgKeys.java
@@ -246,7 +246,7 @@
     }
   }
 
-  private final AccountExternalId.Key toExtIdKey(byte[] fp) {
+  private AccountExternalId.Key toExtIdKey(byte[] fp) {
     return new AccountExternalId.Key(
         AccountExternalId.SCHEME_GPGKEY,
         BaseEncoding.base16().encode(fp));
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/clippy/client/ClippyResources.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/clippy/client/ClippyResources.java
index f3435cc..a97b392 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/clippy/client/ClippyResources.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/clippy/client/ClippyResources.java
@@ -21,7 +21,7 @@
 import com.google.gwt.resources.client.ImageResource;
 
 public interface ClippyResources extends ClientBundle {
-  public static final ClippyResources I = GWT.create(ClippyResources.class);
+  ClippyResources I = GWT.create(ClippyResources.class);
 
   @Source("clippy.css")
   ClippyCss css();
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/clippy/client/CopyableLabelText.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/clippy/client/CopyableLabelText.java
index 4d1b837..8e4d090 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/clippy/client/CopyableLabelText.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/clippy/client/CopyableLabelText.java
@@ -18,7 +18,7 @@
 import com.google.gwt.i18n.client.Constants;
 
 interface CopyableLabelText extends Constants {
-  static final CopyableLabelText I = GWT.create(CopyableLabelText.class);
+  CopyableLabelText I = GWT.create(CopyableLabelText.class);
 
   String tooltip();
   String copied();
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.java
index d26ca8c..2b5984d 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.java
@@ -18,7 +18,7 @@
 import com.google.gwt.i18n.client.Constants;
 
 public interface KeyConstants extends Constants {
-  public static final KeyConstants I = GWT.create(KeyConstants.class);
+  KeyConstants I = GWT.create(KeyConstants.class);
 
   String applicationSection();
   String showHelp();
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyResources.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyResources.java
index a52ca2a..562e12d 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyResources.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyResources.java
@@ -18,7 +18,7 @@
 import com.google.gwt.resources.client.ClientBundle;
 
 public interface KeyResources extends ClientBundle {
-  public static final KeyResources I = GWT.create(KeyResources.class);
+  KeyResources I = GWT.create(KeyResources.class);
 
   @Source("key.css")
   KeyCss css();
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/progress/client/ProgressResources.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/progress/client/ProgressResources.java
index 0276e9a..6bcf2c4 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/progress/client/ProgressResources.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/progress/client/ProgressResources.java
@@ -18,7 +18,7 @@
 import com.google.gwt.resources.client.ClientBundle;
 
 public interface ProgressResources extends ClientBundle {
-  public static final ProgressResources I = GWT.create(ProgressResources.class);
+  ProgressResources I = GWT.create(ProgressResources.class);
 
   @Source("progress.css")
   ProgressCss css();
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/AttMap.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/AttMap.java
index 6eaa7fd..a84835e 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/AttMap.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/AttMap.java
@@ -102,7 +102,7 @@
     }
   }
 
-  private static interface Tag {
+  private interface Tag {
     void assertSafe(String name, String value);
   }
 
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/user/client/Tooltip.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/user/client/Tooltip.java
index e3ab034..7939697 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/user/client/Tooltip.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/user/client/Tooltip.java
@@ -23,7 +23,7 @@
 /** Displays custom tooltip message below an element. */
 public class Tooltip {
   interface Resources extends ClientBundle {
-    static final Resources I = GWT.create(Resources.class);
+    Resources I = GWT.create(Resources.class);
 
     @Source("tooltip.css")
     Css css();
diff --git a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/CommonConstants.java b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/CommonConstants.java
index 032c47c..5d0b93f 100644
--- a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/CommonConstants.java
+++ b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/CommonConstants.java
@@ -18,7 +18,7 @@
 import com.google.gwt.i18n.client.Constants;
 
 public interface CommonConstants extends Constants {
-  public static final CommonConstants C = GWT.create(CommonConstants.class);
+  CommonConstants C = GWT.create(CommonConstants.class);
 
   String inTheFuture();
   String month();
diff --git a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/CommonMessages.java b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/CommonMessages.java
index aa5e3cf..5a5b4a3 100644
--- a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/CommonMessages.java
+++ b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/CommonMessages.java
@@ -18,7 +18,7 @@
 import com.google.gwt.i18n.client.Messages;
 
 public interface CommonMessages extends Messages {
-  public static final CommonMessages M = GWT.create(CommonMessages.class);
+  CommonMessages M = GWT.create(CommonMessages.class);
 
   String secondsAgo(long seconds);
   String minutesAgo(long minutes);
diff --git a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/AccountInfo.java b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/AccountInfo.java
index 6ac0404..830dcb3 100644
--- a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/AccountInfo.java
+++ b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/AccountInfo.java
@@ -40,9 +40,9 @@
     return ts;
   }
 
-  private final native String registeredOnRaw() /*-{ return this.registered_on; }-*/;
-  private final native Timestamp _getRegisteredOn() /*-{ return this._cts; }-*/;
-  private final native void _setRegisteredOn(Timestamp ts) /*-{ this._cts = ts; }-*/;
+  private native String registeredOnRaw() /*-{ return this.registered_on; }-*/;
+  private native Timestamp _getRegisteredOn() /*-{ return this._cts; }-*/;
+  private native void _setRegisteredOn(Timestamp ts) /*-{ this._cts = ts; }-*/;
 
   /**
    * @return true if the server supplied avatar information about this account.
@@ -64,7 +64,7 @@
     return null;
   }
 
-  private final native JsArray<AvatarInfo> avatars()
+  private native JsArray<AvatarInfo> avatars()
   /*-{ return this.avatars }-*/;
 
   public final native void name(String n) /*-{ this.name = n }-*/;
diff --git a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/AuthInfo.java b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/AuthInfo.java
index 15d1c6c..0e3c32b 100644
--- a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/AuthInfo.java
+++ b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/AuthInfo.java
@@ -90,8 +90,8 @@
   public final native String editFullNameUrl() /*-{ return this.edit_full_name_url; }-*/;
   public final native String httpPasswordUrl() /*-{ return this.http_password_url; }-*/;
   public final native boolean isGitBasicAuth() /*-{ return this.is_git_basic_auth || false; }-*/;
-  private final native String authTypeRaw() /*-{ return this.auth_type; }-*/;
-  private final native JsArrayString _editableAccountFields()
+  private native String authTypeRaw() /*-{ return this.auth_type; }-*/;
+  private native JsArrayString _editableAccountFields()
   /*-{ return this.editable_account_fields; }-*/;
 
   protected AuthInfo() {
diff --git a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/ChangeInfo.java b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/ChangeInfo.java
index 2c85556..1153270 100644
--- a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/ChangeInfo.java
+++ b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/ChangeInfo.java
@@ -71,8 +71,8 @@
     return revList.get(revList.length() - 1).isEdit();
   }
 
-  private final native Timestamp _getCts() /*-{ return this._cts; }-*/;
-  private final native void _setCts(Timestamp ts) /*-{ this._cts = ts; }-*/;
+  private native Timestamp _getCts() /*-{ return this._cts; }-*/;
+  private native void _setCts(Timestamp ts) /*-{ this._cts = ts; }-*/;
 
   public final Timestamp updated() {
     return JavaSqlTimestamp_JsonSerializer.parseTimestamp(updatedRaw());
@@ -112,12 +112,12 @@
   public final native boolean mergeable() /*-{ return this.mergeable ? true : false; }-*/;
   public final native int insertions() /*-{ return this.insertions; }-*/;
   public final native int deletions() /*-{ return this.deletions; }-*/;
-  private final native String statusRaw() /*-{ return this.status; }-*/;
+  private native String statusRaw() /*-{ return this.status; }-*/;
   public final native String subject() /*-{ return this.subject; }-*/;
   public final native AccountInfo owner() /*-{ return this.owner; }-*/;
-  private final native String createdRaw() /*-{ return this.created; }-*/;
-  private final native String updatedRaw() /*-{ return this.updated; }-*/;
-  private final native String submittedRaw() /*-{ return this.submitted; }-*/;
+  private native String createdRaw() /*-{ return this.created; }-*/;
+  private native String updatedRaw() /*-{ return this.updated; }-*/;
+  private native String submittedRaw() /*-{ return this.submitted; }-*/;
   public final native boolean starred() /*-{ return this.starred ? true : false; }-*/;
   public final native boolean reviewed() /*-{ return this.reviewed ? true : false; }-*/;
   public final native NativeMap<LabelInfo> allLabels() /*-{ return this.labels; }-*/;
@@ -142,7 +142,7 @@
   public final native JsArray<AccountInfo> removableReviewers()
   /*-{ return this.removable_reviewers; }-*/;
 
-  private final native NativeMap<JsArray<AccountInfo>> _reviewers()
+  private native NativeMap<JsArray<AccountInfo>> _reviewers()
   /*-{ return this.reviewers; }-*/;
   public final Map<ReviewerState, List<AccountInfo>> reviewers() {
     NativeMap<JsArray<AccountInfo>> reviewers = _reviewers();
@@ -173,14 +173,14 @@
     }
     return SubmitType.valueOf(submitType);
   }
-  private final native String _submitType() /*-{ return this.submit_type; }-*/;
+  private native String _submitType() /*-{ return this.submit_type; }-*/;
 
   public final boolean submittable() {
     init();
     return _submittable();
   }
 
-  private final native boolean _submittable()
+  private native boolean _submittable()
   /*-{ return this.submittable ? true : false; }-*/;
 
   /**
@@ -259,7 +259,7 @@
       return null;
     }
 
-    private final native NativeMap<NativeString> _values() /*-{ return this.values; }-*/;
+    private native NativeMap<NativeString> _values() /*-{ return this.values; }-*/;
     public final Set<String> values() {
       return Natives.keys(_values());
     }
@@ -334,7 +334,7 @@
       revisionInfo.takeFromEdit(edit);
       return revisionInfo;
     }
-    private final native void takeFromEdit(EditInfo edit) /*-{
+    private native void takeFromEdit(EditInfo edit) /*-{
       this._number = 0;
       this.name = edit.name;
       this.commit = edit.commit;
@@ -435,7 +435,7 @@
   public static class GitPerson extends JavaScriptObject {
     public final native String name() /*-{ return this.name; }-*/;
     public final native String email() /*-{ return this.email; }-*/;
-    private final native String dateRaw() /*-{ return this.date; }-*/;
+    private native String dateRaw() /*-{ return this.date; }-*/;
 
     public final Timestamp date() {
       return JavaSqlTimestamp_JsonSerializer.parseTimestamp(dateRaw());
@@ -449,7 +449,7 @@
     public final native AccountInfo author() /*-{ return this.author; }-*/;
     public final native String message() /*-{ return this.message; }-*/;
     public final native int _revisionNumber() /*-{ return this._revision_number || 0; }-*/;
-    private final native String dateRaw() /*-{ return this.date; }-*/;
+    private native String dateRaw() /*-{ return this.date; }-*/;
 
     public final Timestamp date() {
       return JavaSqlTimestamp_JsonSerializer.parseTimestamp(dateRaw());
@@ -475,7 +475,7 @@
     public final native JsArrayString branches() /*-{ return this.branches; }-*/;
     public final native JsArrayString tags() /*-{ return this.tags; }-*/;
     public final native JsArrayString external(String n) /*-{ return this.external[n]; }-*/;
-    private final native NativeMap<JsArrayString> external() /*-{ return this.external; }-*/;
+    private native NativeMap<JsArrayString> external() /*-{ return this.external; }-*/;
 
     protected IncludedInInfo() {
     }
diff --git a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/DownloadInfo.java b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/DownloadInfo.java
index eee2847..183e6af 100644
--- a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/DownloadInfo.java
+++ b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/DownloadInfo.java
@@ -39,8 +39,8 @@
   }
 
   public final native DownloadSchemeInfo scheme(String n) /*-{ return this.schemes[n]; }-*/;
-  private final native NativeMap<DownloadSchemeInfo> _schemes() /*-{ return this.schemes; }-*/;
-  private final native JsArrayString _archives() /*-{ return this.archives; }-*/;
+  private native NativeMap<DownloadSchemeInfo> _schemes() /*-{ return this.schemes; }-*/;
+  private native JsArrayString _archives() /*-{ return this.archives; }-*/;
 
   protected DownloadInfo() {
   }
@@ -96,8 +96,8 @@
     public final native boolean isAuthSupported() /*-{ return this.is_auth_supported || false; }-*/;
     public final native String command(String n) /*-{ return this.commands[n]; }-*/;
     public final native String cloneCommand(String n) /*-{ return this.clone_commands[n]; }-*/;
-    private final native NativeMap<NativeString> _commands() /*-{ return this.commands; }-*/;
-    private final native NativeMap<NativeString> _cloneCommands() /*-{ return this.clone_commands; }-*/;
+    private native NativeMap<NativeString> _commands() /*-{ return this.commands; }-*/;
+    private native NativeMap<NativeString> _cloneCommands() /*-{ return this.clone_commands; }-*/;
 
     protected DownloadSchemeInfo() {
     }
diff --git a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/FileInfo.java b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/FileInfo.java
index 555e06e..9b290a5 100644
--- a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/FileInfo.java
+++ b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/FileInfo.java
@@ -37,12 +37,12 @@
   public final long size() {
     return (long)_size();
   }
-  private final native double _size() /*-{ return this.size || 0; }-*/;
+  private native double _size() /*-{ return this.size || 0; }-*/;
 
   public final long sizeDelta() {
     return (long)_sizeDelta();
   }
-  private final native double _sizeDelta() /*-{ return this.size_delta || 0; }-*/;
+  private native double _sizeDelta() /*-{ return this.size_delta || 0; }-*/;
 
   public final native int _row() /*-{ return this._row }-*/;
   public final native void _row(int r) /*-{ this._row = r }-*/;
diff --git a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/GeneralPreferences.java b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/GeneralPreferences.java
index 40e6278..45953cb 100644
--- a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/GeneralPreferences.java
+++ b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/GeneralPreferences.java
@@ -65,7 +65,7 @@
         ? changesPerPage
         : GeneralPreferencesInfo.DEFAULT_PAGESIZE;
   }
-  private final native short get(String n, int d)
+  private native short get(String n, int d)
   /*-{ return this.hasOwnProperty(n) ? this[n] : d }-*/;
 
   public final native boolean showSiteHeader()
@@ -81,21 +81,21 @@
     String s = downloadCommandRaw();
     return s != null ? DownloadCommand.valueOf(s) : null;
   }
-  private final native String downloadCommandRaw()
+  private native String downloadCommandRaw()
   /*-{ return this.download_command }-*/;
 
   public final DateFormat dateFormat() {
     String s = dateFormatRaw();
     return s != null ? DateFormat.valueOf(s) : null;
   }
-  private final native String dateFormatRaw()
+  private native String dateFormatRaw()
   /*-{ return this.date_format }-*/;
 
   public final TimeFormat timeFormat() {
     String s = timeFormatRaw();
     return s != null ? TimeFormat.valueOf(s) : null;
   }
-  private final native String timeFormatRaw()
+  private native String timeFormatRaw()
   /*-{ return this.time_format }-*/;
 
   public final native boolean relativeDateInChangeTable()
@@ -117,14 +117,14 @@
     String s = reviewCategeoryStrategyRaw();
     return s != null ? ReviewCategoryStrategy.valueOf(s) : ReviewCategoryStrategy.NONE;
   }
-  private final native String reviewCategeoryStrategyRaw()
+  private native String reviewCategeoryStrategyRaw()
   /*-{ return this.review_category_strategy }-*/;
 
   public final DiffView diffView() {
     String s = diffViewRaw();
     return s != null ? DiffView.valueOf(s) : null;
   }
-  private final native String diffViewRaw()
+  private native String diffViewRaw()
   /*-{ return this.diff_view }-*/;
 
   public final EmailStrategy emailStrategy() {
@@ -132,7 +132,7 @@
     return s != null ? EmailStrategy.valueOf(s) : null;
   }
 
-  private final native String emailStrategyRaw()
+  private native String emailStrategyRaw()
   /*-{ return this.email_strategy }-*/;
 
   public final native JsArray<TopMenuItem> my()
@@ -159,13 +159,13 @@
   public final void dateFormat(DateFormat f) {
     dateFormatRaw(f != null ? f.toString() : null);
   }
-  private final native void dateFormatRaw(String f)
+  private native void dateFormatRaw(String f)
   /*-{ this.date_format = f }-*/;
 
   public final void timeFormat(TimeFormat f) {
     timeFormatRaw(f != null ? f.toString() : null);
   }
-  private final native void timeFormatRaw(String f)
+  private native void timeFormatRaw(String f)
   /*-{ this.time_format = f }-*/;
 
   public final native void relativeDateInChangeTable(boolean d)
@@ -186,19 +186,19 @@
   public final void reviewCategoryStrategy(ReviewCategoryStrategy s) {
     reviewCategoryStrategyRaw(s != null ? s.toString() : null);
   }
-  private final native void reviewCategoryStrategyRaw(String s)
+  private native void reviewCategoryStrategyRaw(String s)
   /*-{ this.review_category_strategy = s }-*/;
 
   public final void diffView(DiffView d) {
     diffViewRaw(d != null ? d.toString() : null);
   }
-  private final native void diffViewRaw(String d)
+  private native void diffViewRaw(String d)
   /*-{ this.diff_view = d }-*/;
 
   public final void emailStrategy(EmailStrategy s) {
     emailStrategyRaw(s != null ? s.toString() : null);
   }
-  private final native void emailStrategyRaw(String s)
+  private native void emailStrategyRaw(String s)
   /*-{ this.email_strategy = s }-*/;
 
   public final void setMyMenus(List<TopMenuItem> myMenus) {
@@ -218,8 +218,8 @@
     return urlAliases;
   }
 
-  private final native String urlAliasToken(String m) /*-{ return this.url_aliases[m]; }-*/;
-  private final native NativeMap<NativeString> _urlAliases() /*-{ return this.url_aliases; }-*/;
+  private native String urlAliasToken(String m) /*-{ return this.url_aliases[m]; }-*/;
+  private native NativeMap<NativeString> _urlAliases() /*-{ return this.url_aliases; }-*/;
 
   public final void setUrlAliases(Map<String, String> urlAliases) {
     initUrlAliases();
@@ -227,8 +227,8 @@
       putUrlAlias(e.getKey(), e.getValue());
     }
   }
-  private final native void putUrlAlias(String m, String t) /*-{ this.url_aliases[m] = t; }-*/;
-  private final native void initUrlAliases() /*-{ this.url_aliases = {}; }-*/;
+  private native void putUrlAlias(String m, String t) /*-{ this.url_aliases[m] = t; }-*/;
+  private native void initUrlAliases() /*-{ this.url_aliases = {}; }-*/;
 
   protected GeneralPreferences() {
   }
diff --git a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/GitwebInfo.java b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/GitwebInfo.java
index eb5a697..93bd6c6 100644
--- a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/GitwebInfo.java
+++ b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/GitwebInfo.java
@@ -156,7 +156,7 @@
     return url() + pattern.replace(p);
   }
 
-  private final String encode(String segment) {
+  private String encode(String segment) {
     if (type().urlEncode()) {
       return URL.encodeQueryString(type().replacePathSeparator(segment));
     } else {
diff --git a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/GpgKeyInfo.java b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/GpgKeyInfo.java
index f7477a1..7955347 100644
--- a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/GpgKeyInfo.java
+++ b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/GpgKeyInfo.java
@@ -27,7 +27,7 @@
   public final native JsArrayString userIds() /*-{ return this.user_ids; }-*/;
   public final native String key() /*-{ return this.key; }-*/;
 
-  private final native String statusRaw() /*-{ return this.status; }-*/;
+  private native String statusRaw() /*-{ return this.status; }-*/;
   public final Status status() {
     String s = statusRaw();
     if (s == null) {
diff --git a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/ServerInfo.java b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/ServerInfo.java
index b0e52fa..66a859a 100644
--- a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/ServerInfo.java
+++ b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/ServerInfo.java
@@ -18,6 +18,7 @@
 import com.google.gerrit.client.rpc.NativeString;
 import com.google.gerrit.client.rpc.Natives;
 import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArrayString;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -43,7 +44,7 @@
   }
 
   public final native String urlAliasToken(String n) /*-{ return this.url_aliases[n]; }-*/;
-  private final native NativeMap<NativeString> _urlAliases() /*-{ return this.url_aliases; }-*/;
+  private native NativeMap<NativeString> _urlAliases() /*-{ return this.url_aliases; }-*/;
 
 
   public final boolean hasSshd() {
@@ -68,6 +69,8 @@
 
   public static class PluginConfigInfo extends JavaScriptObject {
     public final native boolean hasAvatars() /*-{ return this.has_avatars || false; }-*/;
+    public final native JsArrayString jsResourcePaths() /*-{
+        return this.js_resource_paths || []; }-*/;
 
     protected PluginConfigInfo() {
     }
diff --git a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/rpc/NativeString.java b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/rpc/NativeString.java
index 0e16dc0..572d454 100644
--- a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/rpc/NativeString.java
+++ b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/rpc/NativeString.java
@@ -22,7 +22,7 @@
   public static final JavaScriptObject TYPE = init();
 
   // Used from core and plugins
-  private static final native JavaScriptObject init() /*-{
+  private static native JavaScriptObject init() /*-{
     if ($wnd.Gerrit === undefined || $wnd.Gerrit.JsonString === undefined) {
       return function(s){this.s=s};
     } else {
@@ -30,16 +30,16 @@
     }
   }-*/;
 
-  static final NativeString wrap(String s) {
+  static NativeString wrap(String s) {
     return wrap0(TYPE, s);
   }
 
-  private static final native NativeString wrap0(JavaScriptObject T, String s)
+  private static native NativeString wrap0(JavaScriptObject T, String s)
   /*-{ return new T(s) }-*/;
 
-  public final native String asString() /*-{ return this.s; }-*/;
+  public native String asString() /*-{ return this.s; }-*/;
 
-  public static final AsyncCallback<NativeString>
+  public static AsyncCallback<NativeString>
   unwrap(final AsyncCallback<String> cb) {
     return new AsyncCallback<NativeString>() {
       @Override
@@ -54,11 +54,11 @@
     };
   }
 
-  public static final boolean is(JavaScriptObject o) {
+  public static boolean is(JavaScriptObject o) {
     return is(TYPE, o);
   }
 
-  private static final native boolean is(JavaScriptObject T, JavaScriptObject o)
+  private static native boolean is(JavaScriptObject T, JavaScriptObject o)
   /*-{ return o instanceof T }-*/;
 
   protected NativeString() {
diff --git a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/rpc/TransformCallback.java b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/rpc/TransformCallback.java
index 93c86a2..00e6bb1 100644
--- a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/rpc/TransformCallback.java
+++ b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/rpc/TransformCallback.java
@@ -17,7 +17,7 @@
 import com.google.gwt.user.client.rpc.AsyncCallback;
 
 /** Transforms a value and passes it on to another callback. */
-public abstract class TransformCallback<I, O> implements AsyncCallback<I>{
+public abstract class TransformCallback<I, O> implements AsyncCallback<I> {
   private final AsyncCallback<O> callback;
 
   protected TransformCallback(AsyncCallback<O> callback) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/AvatarImage.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/AvatarImage.java
index bec89cc..b2da7b5 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/AvatarImage.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/AvatarImage.java
@@ -138,7 +138,7 @@
     private Timer showTimer;
     private Timer hideTimer;
 
-    public PopupHandler(AccountInfo account, UIObject target) {
+    PopupHandler(AccountInfo account, UIObject target) {
       this.account = account;
       this.target = target;
     }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
index 79b4135..7875ae8 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
@@ -88,7 +88,6 @@
 import com.google.gerrit.client.editor.EditScreen;
 import com.google.gerrit.client.groups.GroupApi;
 import com.google.gerrit.client.groups.GroupInfo;
-import com.google.gerrit.client.patches.UnifiedPatchScreen;
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.client.rpc.RestApi;
 import com.google.gerrit.client.ui.Screen;
@@ -425,7 +424,7 @@
       int line = 0;
       int at = rest.lastIndexOf('@');
       if (at > 0) {
-        String l = rest.substring(at+1);
+        String l = rest.substring(at + 1);
         if (l.startsWith("a")) {
           side = DisplaySide.A;
           l = l.substring(1);
@@ -486,8 +485,6 @@
       codemirror(token, baseId, id, side, line, false);
     } else if ("unified".equals(panel)) {
       unified(token, baseId, id, side, line);
-    } else if ("unified1".equals(panel)) {
-      unified1(token, baseId, id);
     } else if ("edit".equals(panel)) {
       codemirror(token, null, id, side, line, true);
     } else {
@@ -511,18 +508,6 @@
     });
   }
 
-  private static void unified1(final String token,
-      final PatchSet.Id baseId,
-      final Patch.Key id) {
-    GWT.runAsync(new AsyncSplit(token) {
-      @Override
-      public void onSuccess() {
-        UnifiedPatchScreen.TopView top = Gerrit.getPatchScreenTopView();
-        Gerrit.display(token, new UnifiedPatchScreen(id, top, baseId));
-      }
-    });
-  }
-
   private static void codemirror(final String token, final PatchSet.Id baseId,
       final Patch.Key id, final DisplaySide side, final int line,
       final boolean edit) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
index efa4612..7c2a280 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
@@ -37,7 +37,6 @@
 import com.google.gerrit.client.info.TopMenu;
 import com.google.gerrit.client.info.TopMenuItem;
 import com.google.gerrit.client.info.TopMenuList;
-import com.google.gerrit.client.patches.UnifiedPatchScreen;
 import com.google.gerrit.client.rpc.CallbackGroup;
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.client.rpc.Natives;
@@ -56,7 +55,6 @@
 import com.google.gwt.aria.client.Roles;
 import com.google.gwt.core.client.EntryPoint;
 import com.google.gwt.core.client.GWT;
-import com.google.gwt.dom.client.AnchorElement;
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
@@ -138,7 +136,6 @@
   private static SearchPanel searchPanel;
   private static final Dispatcher dispatcher = new Dispatcher();
   private static ViewSite<Screen> body;
-  private static UnifiedPatchScreen patchScreen;
   private static String lastChangeListToken;
   private static String lastViewToken;
 
@@ -152,13 +149,6 @@
     Window.Location.reload();
   }
 
-  public static UnifiedPatchScreen.TopView getPatchScreenTopView() {
-    if (patchScreen == null) {
-      return null;
-    }
-    return patchScreen.getTopView();
-  }
-
   public static void displayLastChangeList() {
     if (lastChangeListToken != null) {
       display(lastChangeListToken);
@@ -214,26 +204,6 @@
     }
   }
 
-  /**
-   * Update any top level menus which can vary based on the view which was
-   * loaded.
-   * @param view the loaded view.
-   */
-  public static void updateMenus(Screen view) {
-    LinkMenuBar diffBar = menuBars.get(GerritTopMenu.DIFFERENCES.menuName);
-    if (view instanceof UnifiedPatchScreen) {
-      patchScreen = (UnifiedPatchScreen) view;
-      menuLeft.setVisible(diffBar, true);
-      menuLeft.selectTab(menuLeft.getWidgetIndex(diffBar));
-    } else {
-      if (patchScreen != null && menuLeft.getSelectedWidget() == diffBar) {
-        menuLeft.selectTab(isSignedIn() ? 1 : 0);
-      }
-      patchScreen = null;
-      menuLeft.setVisible(diffBar, false);
-    }
-  }
-
   public static void selectMenu(LinkMenuBar bar) {
     menuLeft.selectTab(menuLeft.getWidgetIndex(bar));
   }
@@ -718,15 +688,6 @@
       menuLeft.selectTab(0);
     }
 
-    patchScreen = null;
-    LinkMenuBar diffBar = new LinkMenuBar();
-    menuBars.put(GerritTopMenu.DIFFERENCES.menuName, diffBar);
-    menuLeft.addInvisible(diffBar, C.menuDiff());
-    addDiffLink(diffBar, C.menuDiffCommit(), UnifiedPatchScreen.TopView.COMMIT);
-    addDiffLink(diffBar, C.menuDiffPreferences(), UnifiedPatchScreen.TopView.PREFERENCES);
-    addDiffLink(diffBar, C.menuDiffPatchSets(), UnifiedPatchScreen.TopView.PATCH_SETS);
-    addDiffLink(diffBar, C.menuDiffFiles(), UnifiedPatchScreen.TopView.FILES);
-
     final LinkMenuBar projectsBar = new LinkMenuBar();
     menuBars.put(GerritTopMenu.PROJECTS.menuName, projectsBar);
     addLink(projectsBar, C.menuProjectsList(), PageLinks.ADMIN_PROJECTS);
@@ -975,7 +936,7 @@
 
       @Override
       public void onKeyDown(KeyDownEvent event) {
-        if(event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
+        if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
           showHidePopup();
           event.preventDefault();
         }
@@ -1018,19 +979,6 @@
     m.insertItem(new LinkMenuItem(text, historyToken), beforeIndex);
   }
 
-  private static void addDiffLink(final LinkMenuBar m, final String text,
-      final UnifiedPatchScreen.TopView tv) {
-    m.addItem(new LinkMenuItem(text, "") {
-        @Override
-        public void go() {
-          if (patchScreen != null) {
-            patchScreen.setTopView(tv);
-          }
-          AnchorElement.as(getElement()).blur();
-        }
-      });
-  }
-
   private static LinkMenuItem addProjectLink(LinkMenuBar m, TopMenuItem item) {
     LinkMenuItem i = new ProjectLinkMenuItem(item.getName(), item.getUrl()) {
         @Override
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchSuggestOracle.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchSuggestOracle.java
index afbaf85..920c285 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchSuggestOracle.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchSuggestOracle.java
@@ -29,7 +29,9 @@
   private static final List<ParamSuggester> paramSuggester = Arrays.asList(
       new ParamSuggester(Arrays.asList("project:", "parentproject:"),
           new ProjectNameSuggestOracle()),
-      new ParamSuggester(Arrays.asList("owner:", "reviewer:"),
+      new ParamSuggester(Arrays.asList(
+          "owner:", "reviewer:", "commentby:", "reviewedby:", "author:",
+          "committer:", "from:"),
           new AccountSuggestOracle() {
             @Override
             public void onRequestSuggestions(final Request request, final Callback done) {
@@ -124,6 +126,7 @@
     suggestions.add("status:closed");
     suggestions.add("status:merged");
     suggestions.add("status:abandoned");
+    suggestions.add("status:draft");
 
     suggestions.add("added:");
     suggestions.add("deleted:");
@@ -205,7 +208,7 @@
   private static class SearchSuggestion implements SuggestOracle.Suggestion {
     private final String suggestion;
     private final String fullQuery;
-    public SearchSuggestion(String suggestion, String fullQuery) {
+    SearchSuggestion(String suggestion, String fullQuery) {
       this.suggestion = suggestion;
       // Add a space to the query if it is a complete operation (e.g.
       // "status:open") so the user can keep on typing.
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/DiffPreferences.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/DiffPreferences.java
index 7d543d8..a3fc6dd 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/DiffPreferences.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/DiffPreferences.java
@@ -44,6 +44,7 @@
     p.theme(in.theme);
     p.hideEmptyPane(in.hideEmptyPane);
     p.retainHeader(in.retainHeader);
+    p.skipUnchanged(in.skipUnchanged);
     p.skipUncommented(in.skipUncommented);
     p.skipDeleted(in.skipDeleted);
     p.matchBrackets(in.matchBrackets);
@@ -63,6 +64,7 @@
     p.showTabs = showTabs();
     p.showWhitespaceErrors = showWhitespaceErrors();
     p.skipDeleted = skipDeleted();
+    p.skipUnchanged = skipUnchanged();
     p.skipUncommented = skipUncommented();
     p.syntaxHighlighting = syntaxHighlighting();
     p.hideTopMenu = hideTopMenu();
@@ -138,6 +140,7 @@
   public final native void renderEntireFile(boolean r) /*-{ this.render_entire_file = r }-*/;
   public final native void retainHeader(boolean r) /*-{ this.retain_header = r }-*/;
   public final native void hideEmptyPane(boolean s) /*-{ this.hide_empty_pane = s }-*/;
+  public final native void skipUnchanged(boolean s) /*-{ this.skip_unchanged = s }-*/;
   public final native void skipUncommented(boolean s) /*-{ this.skip_uncommented = s }-*/;
   public final native void skipDeleted(boolean s) /*-{ this.skip_deleted = s }-*/;
   public final native void matchBrackets(boolean m) /*-{ this.match_brackets = m }-*/;
@@ -154,15 +157,16 @@
   public final native boolean renderEntireFile() /*-{ return this.render_entire_file || false }-*/;
   public final native boolean hideEmptyPane() /*-{ return this.hide_empty_pane || false }-*/;
   public final native boolean retainHeader() /*-{ return this.retain_header || false }-*/;
+  public final native boolean skipUnchanged() /*-{ return this.skip_unchanged || false }-*/;
   public final native boolean skipUncommented() /*-{ return this.skip_uncommented || false }-*/;
   public final native boolean skipDeleted() /*-{ return this.skip_deleted || false }-*/;
   public final native boolean matchBrackets() /*-{ return this.match_brackets || false }-*/;
 
-  private final native void setThemeRaw(String i) /*-{ this.theme = i }-*/;
-  private final native void setIgnoreWhitespaceRaw(String i) /*-{ this.ignore_whitespace = i }-*/;
-  private final native String ignoreWhitespaceRaw() /*-{ return this.ignore_whitespace }-*/;
-  private final native String themeRaw() /*-{ return this.theme }-*/;
-  private final native int get(String n, int d) /*-{ return this.hasOwnProperty(n) ? this[n] : d }-*/;
+  private native void setThemeRaw(String i) /*-{ this.theme = i }-*/;
+  private native void setIgnoreWhitespaceRaw(String i) /*-{ this.ignore_whitespace = i }-*/;
+  private native String ignoreWhitespaceRaw() /*-{ return this.ignore_whitespace }-*/;
+  private native String themeRaw() /*-{ return this.theme }-*/;
+  private native int get(String n, int d) /*-{ return this.hasOwnProperty(n) ? this[n] : d }-*/;
 
   protected DiffPreferences() {
   }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/EditPreferences.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/EditPreferences.java
index d37ddd5..8ed7f76 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/EditPreferences.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/EditPreferences.java
@@ -24,6 +24,7 @@
     EditPreferences p = createObject().cast();
     p.tabSize(in.tabSize);
     p.lineLength(in.lineLength);
+    p.indentUnit(in.indentUnit);
     p.cursorBlinkRate(in.cursorBlinkRate);
     p.hideTopMenu(in.hideTopMenu);
     p.showTabs(in.showTabs);
@@ -40,6 +41,7 @@
   public final EditPreferencesInfo copyTo(EditPreferencesInfo p) {
     p.tabSize = tabSize();
     p.lineLength = lineLength();
+    p.indentUnit = indentUnit();
     p.cursorBlinkRate = cursorBlinkRate();
     p.hideTopMenu = hideTopMenu();
     p.showTabs = showTabs();
@@ -56,15 +58,16 @@
   public final void theme(Theme i) {
     setThemeRaw(i != null ? i.toString() : Theme.DEFAULT.toString());
   }
-  private final native void setThemeRaw(String i) /*-{ this.theme = i }-*/;
+  private native void setThemeRaw(String i) /*-{ this.theme = i }-*/;
 
   public final void keyMapType(KeyMapType i) {
     setkeyMapTypeRaw(i != null ? i.toString() : KeyMapType.DEFAULT.toString());
   }
-  private final native void setkeyMapTypeRaw(String i) /*-{ this.key_map_type = i }-*/;
+  private native void setkeyMapTypeRaw(String i) /*-{ this.key_map_type = i }-*/;
 
   public final native void tabSize(int t) /*-{ this.tab_size = t }-*/;
   public final native void lineLength(int c) /*-{ this.line_length = c }-*/;
+  public final native void indentUnit(int c) /*-{ this.indent_unit = c }-*/;
   public final native void cursorBlinkRate(int r) /*-{ this.cursor_blink_rate = r }-*/;
   public final native void hideTopMenu(boolean s) /*-{ this.hide_top_menu = s }-*/;
   public final native void showTabs(boolean s) /*-{ this.show_tabs = s }-*/;
@@ -78,13 +81,13 @@
     String s = themeRaw();
     return s != null ? Theme.valueOf(s) : Theme.DEFAULT;
   }
-  private final native String themeRaw() /*-{ return this.theme }-*/;
+  private native String themeRaw() /*-{ return this.theme }-*/;
 
   public final KeyMapType keyMapType() {
     String s = keyMapTypeRaw();
     return s != null ? KeyMapType.valueOf(s) : KeyMapType.DEFAULT;
   }
-  private final native String keyMapTypeRaw() /*-{ return this.key_map_type }-*/;
+  private native String keyMapTypeRaw() /*-{ return this.key_map_type }-*/;
 
   public final int tabSize() {
     return get("tab_size", 8);
@@ -94,6 +97,10 @@
     return get("line_length", 100);
   }
 
+  public final int indentUnit() {
+    return get("indent_unit", 2);
+  }
+
   public final int cursorBlinkRate() {
     return get("cursor_blink_rate", 0);
   }
@@ -105,7 +112,7 @@
   public final native boolean hideLineNumbers() /*-{ return this.hide_line_numbers || false }-*/;
   public final native boolean matchBrackets() /*-{ return this.match_brackets || false }-*/;
   public final native boolean autoCloseBrackets() /*-{ return this.auto_close_brackets || false }-*/;
-  private final native int get(String n, int d) /*-{ return this.hasOwnProperty(n) ? this[n] : d }-*/;
+  private native int get(String n, int d) /*-{ return this.hasOwnProperty(n) ? this[n] : d }-*/;
 
   protected EditPreferences() {
   }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/SettingsScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/SettingsScreen.java
index e8c58ef..405ef68 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/SettingsScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/SettingsScreen.java
@@ -81,7 +81,7 @@
 
   private void linkByPlugin(String pluginName, String text, String target) {
     if (ambiguousMenuNames.contains(text)) {
-      text += " ("+ pluginName + ")";
+      text += " (" + pluginName + ")";
     }
     link(text, target);
   }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupInfoScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupInfoScreen.java
index cd72686..a71dffe 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupInfoScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupInfoScreen.java
@@ -211,7 +211,9 @@
   protected void display(final GroupInfo group, final boolean canModify) {
     groupUUIDLabel.setText(group.getGroupUUID().get());
     groupNameTxt.setText(group.name());
-    ownerTxt.setText(group.owner() != null?group.owner():Util.M.deletedReference(group.getOwnerUUID().get()));
+    ownerTxt.setText(group.owner() != null
+        ? group.owner()
+        : Util.M.deletedReference(group.getOwnerUUID().get()));
     descTxt.setText(group.description());
     visibleToAllCheckBox.setValue(group.options().isVisibleToAll());
     setMembersTabVisible(AccountGroup.isInternalGroup(group.getGroupUUID()));
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminResources.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminResources.java
index 90ae162..688a59f 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminResources.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminResources.java
@@ -19,7 +19,7 @@
 import com.google.gwt.resources.client.ImageResource;
 
 public interface AdminResources extends ClientBundle {
-  public static final AdminResources I = GWT.create(AdminResources.class);
+  AdminResources I = GWT.create(AdminResources.class);
 
   @Source("admin.css")
   AdminCss css();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupReferenceBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupReferenceBox.java
index c1082bc..d6d0fe3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupReferenceBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupReferenceBox.java
@@ -47,7 +47,7 @@
             toValue(event.getSelectedItem()));
       }
     });
-    suggestBox.addCloseHandler(new CloseHandler<RemoteSuggestBox>(){
+    suggestBox.addCloseHandler(new CloseHandler<RemoteSuggestBox>() {
       @Override
       public void onClose(CloseEvent<RemoteSuggestBox> event) {
         suggestBox.setText("");
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java
index aed1dc2..64fc0e5 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java
@@ -113,7 +113,7 @@
         return a.name().compareTo(b.name());
       }
     });
-    for(GroupInfo group : list.subList(fromIndex, toIndex)) {
+    for (GroupInfo group : list.subList(fromIndex, toIndex)) {
       final int row = table.getRowCount();
       table.insertRow(row);
       applyDataRowStyle(row);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessScreen.java
index 0bf1b4b..6345207 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessScreen.java
@@ -183,7 +183,7 @@
     driver.edit(mock);
   }
 
-  @UiHandler(value={"cancel1", "cancel2"})
+  @UiHandler(value = {"cancel1", "cancel2"})
   void onCancel(@SuppressWarnings("unused") ClickEvent event) {
     Gerrit.display(PageLinks.toProjectAcceess(getProjectKey()));
   }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java
index c6bd1d1..c948a8e 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java
@@ -727,7 +727,7 @@
   private static class LabeledWidgetsGrid extends FlexTable {
     private String labelSuffix;
 
-    public LabeledWidgetsGrid() {
+    LabeledWidgetsGrid() {
       super();
       labelSuffix = ":";
     }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ApiGlue.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ApiGlue.java
index 7a48533..626252a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ApiGlue.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ApiGlue.java
@@ -236,14 +236,14 @@
     }
   }
 
-  private static final String getPluginName() {
+  private static String getPluginName() {
     if (pluginName != null) {
       return pluginName;
     }
     return PluginName.fromUrl(PluginName.getCallerUrl());
   }
 
-  private static final void go(String urlOrToken) {
+  private static void go(String urlOrToken) {
     if (urlOrToken.startsWith("http:")
         || urlOrToken.startsWith("https:")
         || urlOrToken.startsWith("//")) {
@@ -253,35 +253,35 @@
     }
   }
 
-  private static final void refresh() {
+  private static void refresh() {
     Gerrit.display(History.getToken());
   }
 
-  private static final ServerInfo getServerInfo() {
+  private static ServerInfo getServerInfo() {
     return Gerrit.info();
   }
 
-  private static final AccountInfo getCurrentUser() {
+  private static AccountInfo getCurrentUser() {
     return Gerrit.getUserAccount();
   }
 
-  private static final GeneralPreferences getUserPreferences() {
+  private static GeneralPreferences getUserPreferences() {
     return Gerrit.getUserPreferences();
   }
 
-  private static final void refreshUserPreferences() {
+  private static void refreshUserPreferences() {
     Gerrit.refreshUserPreferences();
   }
 
-  private static final void refreshMenuBar() {
+  private static void refreshMenuBar() {
     Gerrit.refreshMenuBar();
   }
 
-  private static final boolean isSignedIn() {
+  private static boolean isSignedIn() {
     return Gerrit.isSignedIn();
   }
 
-  private static final void showError(String message) {
+  private static void showError(String message) {
     new ErrorDialog(message).center();
   }
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ChangeGlue.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ChangeGlue.java
index 82b6810..1e77773 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ChangeGlue.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ChangeGlue.java
@@ -55,11 +55,11 @@
     }
   }
 
-  private static final native JavaScriptObject get(String id) /*-{
+  private static native JavaScriptObject get(String id) /*-{
     return $wnd.Gerrit.change_actions[id];
   }-*/;
 
-  private static final native boolean invoke(JavaScriptObject h,
+  private static native boolean invoke(JavaScriptObject h,
       ChangeInfo a, RevisionInfo r)
   /*-{ return h(a,r) }-*/;
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/EditGlue.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/EditGlue.java
index 49b150a..b7e3df3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/EditGlue.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/EditGlue.java
@@ -45,7 +45,7 @@
     }
   }
 
-  private static final native JavaScriptObject get(String id) /*-{
+  private static native JavaScriptObject get(String id) /*-{
     return $wnd.Gerrit.edit_actions[id];
   }-*/;
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ExtensionPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ExtensionPanel.java
index 0702cba..e20c577 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ExtensionPanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ExtensionPanel.java
@@ -130,14 +130,14 @@
     final native void putBoolean(String k, boolean v) /*-{ this.p[k] = v; }-*/;
     final native void putObject(String k, JavaScriptObject v) /*-{ this.p[k] = v; }-*/;
 
-    private static final native Context create(
+    private static native Context create(
         JavaScriptObject T,
         Definition d,
         Element e)
     /*-{ return new T(d,e) }-*/;
 
     private static final JavaScriptObject TYPE = init();
-    private static final native JavaScriptObject init() /*-{
+    private static native JavaScriptObject init() /*-{
       var T = function(d,e) {
         this._d = d;
         this._u = [];
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ExtensionScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ExtensionScreen.java
index 98b06bb..19dbe06 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ExtensionScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ExtensionScreen.java
@@ -109,7 +109,7 @@
     final native void onLoad() /*-{ this._d.onLoad(this) }-*/;
     final native JsArray<JavaScriptObject> unload() /*-{ return this._u }-*/;
 
-    private static final native Context create(
+    private static native Context create(
         JavaScriptObject T,
         Definition d,
         ExtensionScreen s,
@@ -118,7 +118,7 @@
     /*-{ return new T(d,s,e,m) }-*/;
 
     private static final JavaScriptObject TYPE = init();
-    private static final native JavaScriptObject init() /*-{
+    private static native JavaScriptObject init() /*-{
       var T = function(d,s,e,m) {
         this._d = d;
         this._s = s;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ExtensionSettingsScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ExtensionSettingsScreen.java
index c351bbf..1d7259b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ExtensionSettingsScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ExtensionSettingsScreen.java
@@ -91,7 +91,7 @@
       return Natives.keys(settingsScreens());
     }
 
-    private static final native NativeMap<NativeString> settingsScreens()
+    private static native NativeMap<NativeString> settingsScreens()
     /*-{ return $wnd.Gerrit.settingsScreens; }-*/;
 
     public final native String getPath() /*-{ return this.path; }-*/;
@@ -114,7 +114,7 @@
     final native void onLoad() /*-{ this._d.onLoad(this) }-*/;
     final native JsArray<JavaScriptObject> unload() /*-{ return this._u }-*/;
 
-    private static final native Context create(
+    private static native Context create(
         JavaScriptObject T,
         Definition d,
         ExtensionSettingsScreen s,
@@ -122,7 +122,7 @@
     /*-{ return new T(d,s,e) }-*/;
 
     private static final JavaScriptObject TYPE = init();
-    private static final native JavaScriptObject init() /*-{
+    private static native JavaScriptObject init() /*-{
       var T = function(d,s,e) {
         this._d = d;
         this._s = s;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/HtmlTemplate.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/HtmlTemplate.java
index 95757ab..6af244a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/HtmlTemplate.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/HtmlTemplate.java
@@ -62,19 +62,19 @@
     };
   }-*/;
 
-  private static final String css(String css) {
+  private static String css(String css) {
     String name = DOM.createUniqueId();
     StyleInjector.inject("." + name + "{" + css + "}");
     return name;
   }
 
-  private static final String id(IdMap idMap, String key) {
+  private static String id(IdMap idMap, String key) {
     String id = DOM.createUniqueId();
     idMap.put(id, key);
     return " id='" + id + "'";
   }
 
-  private static final String html(ReplacementMap opts, String id) {
+  private static String html(ReplacementMap opts, String id) {
     int d = id.indexOf('.');
     if (0 < d) {
       String name = id.substring(0, d);
@@ -84,7 +84,7 @@
     return new SafeHtmlBuilder().append(opts.str(id)).asString();
   }
 
-  private static final Node parseHtml(
+  private static Node parseHtml(
       String html,
       IdMap ids,
       ReplacementMap opts,
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/Plugin.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/Plugin.java
index 04d4ce5..fb549ee 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/Plugin.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/Plugin.java
@@ -26,14 +26,14 @@
     return create(TYPE, url, name);
   }
 
-  final native String url() /*-{ return this._scriptUrl }-*/;
-  final native String name() /*-{ return this.name }-*/;
+  native String url() /*-{ return this._scriptUrl }-*/;
+  native String name() /*-{ return this.name }-*/;
 
-  final native boolean loaded() /*-{ return this._success || this._failure != null }-*/;
-  final native Exception failure() /*-{ return this._failure }-*/;
-  final native void failure(Exception e) /*-{ this._failure = e }-*/;
-  final native boolean success() /*-{ return this._success || false }-*/;
-  final native void _initialized() /*-{ this._success = true }-*/;
+  native boolean loaded() /*-{ return this._success || this._failure != null }-*/;
+  native Exception failure() /*-{ return this._failure }-*/;
+  native void failure(Exception e) /*-{ this._failure = e }-*/;
+  native boolean success() /*-{ return this._success || false }-*/;
+  native void _initialized() /*-{ this._success = true }-*/;
 
   private static native Plugin create(JavaScriptObject T, String u, String n)
   /*-{ return new T(u,n) }-*/;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/PluginName.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/PluginName.java
index a560711..330ec15 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/PluginName.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/PluginName.java
@@ -76,7 +76,7 @@
   protected static final native JavaScriptException makeException()
   /*-{ try { null.a() } catch (e) { return e } }-*/;
 
-  private static final native boolean hasStack(JavaScriptException e)
+  private static native boolean hasStack(JavaScriptException e)
   /*-{ return !!e.stack }-*/;
 
   /** Extracts URL from the stack frame. */
@@ -103,7 +103,7 @@
       return UNKNOWN;
     }
 
-    private static final native JsArrayString getStack(JavaScriptException e)
+    private static native JsArrayString getStack(JavaScriptException e)
     /*-{ return e.stack ? e.stack.split('\n') : [] }-*/;
   }
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ProjectGlue.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ProjectGlue.java
index 69887e7..f9084d9 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ProjectGlue.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ProjectGlue.java
@@ -61,11 +61,11 @@
     }
   }
 
-  private static final native JavaScriptObject projectAction(String id) /*-{
+  private static native JavaScriptObject projectAction(String id) /*-{
     return $wnd.Gerrit.project_actions[id];
   }-*/;
 
-  private static final native JavaScriptObject branchAction(String id) /*-{
+  private static native JavaScriptObject branchAction(String id) /*-{
     return $wnd.Gerrit.branch_actions[id];
   }-*/;
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/RevisionGlue.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/RevisionGlue.java
index 914ef85..50ebce7 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/RevisionGlue.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/RevisionGlue.java
@@ -46,7 +46,7 @@
     }
   }
 
-  private static final native JavaScriptObject get(String id) /*-{
+  private static native JavaScriptObject get(String id) /*-{
     return $wnd.Gerrit.revision_actions[id];
   }-*/;
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ActionMessageBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ActionMessageBox.java
index 28943ab..396bc8a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ActionMessageBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ActionMessageBox.java
@@ -35,7 +35,7 @@
   interface Binder extends UiBinder<HTMLPanel, ActionMessageBox> {}
   private static final Binder uiBinder = GWT.create(Binder.class);
 
-  static interface Style extends CssResource {
+  interface Style extends CssResource {
     String popup();
   }
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.java
index 033a3a8..36107ee 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.java
@@ -37,7 +37,7 @@
 class Actions extends Composite {
   private static final String[] CORE = {
     "abandon", "cherrypick", "followup", "hashtags", "publish",
-    "rebase", "restore", "revert", "submit", "topic", "/"};
+    "rebase", "restore", "revert", "submit", "topic", "/",};
 
   interface Binder extends UiBinder<FlowPanel, Actions> {}
   private static final Binder uiBinder = GWT.create(Binder.class);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java
index 71cc7fb..46702ec 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java
@@ -95,7 +95,7 @@
     String restoreDelete();
   }
 
-  public static enum Mode {
+  public enum Mode {
     REVIEW,
     EDIT
   }
@@ -115,7 +115,7 @@
     init(DELETE, RESTORE, REVIEWED, OPEN);
   }
 
-  private static final native void init(String d, String t, String r, String o) /*-{
+  private static native void init(String d, String t, String r, String o) /*-{
     $wnd[d] = $entry(function(e,i) {
       @com.google.gerrit.client.change.FileTable::onDelete(Lcom/google/gwt/dom/client/NativeEvent;I)(e,i)
     });
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Hashtags.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Hashtags.java
index ed117aa..1dc99b4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Hashtags.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Hashtags.java
@@ -62,7 +62,7 @@
     init(REMOVE);
   }
 
-  private static final native void init(String r) /*-{
+  private static native void init(String r) /*-{
     $wnd[r] = $entry(function(e) {
       @com.google.gerrit.client.change.Hashtags::onRemove(Lcom/google/gwt/dom/client/NativeEvent;)(e)
     });
@@ -132,7 +132,7 @@
         ClickEvent.getType());
   }
 
-  void init(ChangeScreen.Style style){
+  void init(ChangeScreen.Style style) {
     this.style = style;
   }
 
@@ -246,12 +246,12 @@
       input.init(toJsArrayString(add), toJsArrayString(remove));
       return input;
     }
-    private static JsArrayString toJsArrayString(String commaSeparated){
+    private static JsArrayString toJsArrayString(String commaSeparated) {
       if (commaSeparated == null || commaSeparated.equals("")) {
         return null;
       }
       JsArrayString array = JsArrayString.createArray().cast();
-      for (String hashtag : commaSeparated.split(",")){
+      for (String hashtag : commaSeparated.split(",")) {
         array.push(hashtag.trim());
       }
       return array;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Labels.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Labels.java
index 827362e..89550c6 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Labels.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Labels.java
@@ -59,7 +59,7 @@
     init(REMOVE_REVIEWER, REMOVE_VOTE);
   }
 
-  private static final native void init(String r, String v) /*-{
+  private static native void init(String r, String v) /*-{
     $wnd[r] = $entry(function(e) {
       @com.google.gerrit.client.change.Labels::onRemoveReviewer(Lcom/google/gwt/dom/client/NativeEvent;)(e)
     });
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/LineComment.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/LineComment.java
index 9873bed..a0f8858 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/LineComment.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/LineComment.java
@@ -57,14 +57,14 @@
       ps = defaultPs;
       psLoc.removeFromParent();
       psLoc = null;
-      psNum= null;
+      psNum = null;
     } else {
       ps = defaultPs;
       sideLoc.removeFromParent();
       sideLoc = null;
       psLoc.removeFromParent();
       psLoc = null;
-      psNum= null;
+      psNum = null;
     }
 
     if (info.hasLine()) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Message.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Message.java
index f53c1a3..6c27ed9 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Message.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Message.java
@@ -50,7 +50,7 @@
   interface Binder extends UiBinder<HTMLPanel, Message> {}
   private static final Binder uiBinder = GWT.create(Binder.class);
 
-  static interface Style extends CssResource {
+  interface Style extends CssResource {
     String closed();
   }
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/PatchSetsBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/PatchSetsBox.java
index 1d76612..1753c7b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/PatchSetsBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/PatchSetsBox.java
@@ -63,7 +63,7 @@
     init(OPEN);
   }
 
-  private static final native void init(String o) /*-{
+  private static native void init(String o) /*-{
     $wnd[o] = $entry(function(e,i) {
       return @com.google.gerrit.client.change.PatchSetsBox::onOpen(Lcom/google/gwt/dom/client/NativeEvent;I)(e,i);
     });
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java
index 9612f71..d222942 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java
@@ -137,7 +137,7 @@
     abstract String getTitle(int count);
     abstract String getTitle(String count);
 
-    private Tab(String defaultTitle, String tooltip) {
+    Tab(String defaultTitle, String tooltip) {
       this.defaultTitle = defaultTitle;
       this.tooltip = tooltip;
     }
@@ -385,7 +385,7 @@
       String s = statusRaw();
       return s != null ? Change.Status.valueOf(s) : null;
     }
-    private final native String statusRaw() /*-{ return this.status; }-*/;
+    private native String statusRaw() /*-{ return this.status; }-*/;
 
     final native void setId(String i)
     /*-{ if(i)this.change_id=i; }-*/;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChangesTab.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChangesTab.java
index cc34df2..788b4b0 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChangesTab.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChangesTab.java
@@ -67,7 +67,7 @@
   private static final SafeHtml POINTER_HTML =
       AbstractImagePrototype.create(Gerrit.RESOURCES.arrowRight()).getSafeHtml();
 
-  private static final native String init(String o) /*-{
+  private static native String init(String o) /*-{
     $wnd[o] = $entry(@com.google.gerrit.client.change.RelatedChangesTab::onOpen(
       Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/dom/client/Element;));
     return o + '(event,this)';
@@ -599,7 +599,7 @@
     }
   }
 
-  private static final native Node createDocumentFragment() /*-{
+  private static native Node createDocumentFragment() /*-{
     return $doc.createDocumentFragment();
   }-*/;
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Resources.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Resources.java
index 4fc76c1..fdfaf61 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Resources.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Resources.java
@@ -19,9 +19,9 @@
 import com.google.gwt.resources.client.CssResource;
 
 public interface Resources extends ClientBundle {
-  public static final Resources I = GWT.create(Resources.class);
-  static final ChangeConstants C = GWT.create(ChangeConstants.class);
-  static final ChangeMessages M = GWT.create(ChangeMessages.class);
+  Resources I = GWT.create(Resources.class);
+  ChangeConstants C = GWT.create(ChangeConstants.class);
+  ChangeMessages M = GWT.create(ChangeMessages.class);
 
   @Source("common.css") Style style();
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Reviewers.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Reviewers.java
index 71942ce..b69d1c0 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Reviewers.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Reviewers.java
@@ -293,7 +293,7 @@
       return Natives.keys(_approvals());
     }
     final native String approval(String l) /*-{ return this.approvals[l]; }-*/;
-    private final native NativeMap<NativeString> _approvals() /*-{ return this.approvals; }-*/;
+    private native NativeMap<NativeString> _approvals() /*-{ return this.approvals; }-*/;
 
     protected ReviewerInfo() {
     }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeApi.java
index bff3f47..b7c8a5e 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeApi.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeApi.java
@@ -170,7 +170,7 @@
   public static RestApi hashtags(int changeId) {
     return change(changeId).view("hashtags");
   }
-  public static RestApi hashtag(int changeId, String hashtag){
+  public static RestApi hashtag(int changeId, String hashtag) {
     return change(changeId).view("hashtags").id(hashtag);
   }
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.java
index 0a97729..157f947 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.java
@@ -111,9 +111,6 @@
   String reviewed();
   String submitFailed();
 
-  String diffAllSideBySide();
-  String diffAllUnified();
-
   String votable();
 
   String pushCertMissing();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.properties
index 5a3ce66..7fe3675 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.properties
@@ -94,9 +94,6 @@
 reviewed = Reviewed
 submitFailed = Submit Failed
 
-diffAllSideBySide = All Side-by-Side
-diffAllUnified = All Unified
-
 votable = Votable:
 
 pushCertMissing = This patch set was created without a push certificate
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeMessages.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeMessages.properties
index 8b96dac..1fe5909 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeMessages.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeMessages.properties
@@ -31,8 +31,8 @@
 copiedFrom = copied from {0}
 otherFrom = from {0}
 
-blockedOn = Blocked on {0}
-needs = Needs {0}
+blockedOn = Blocked on {0} Label
+needs = Needs {0} Label
 publishComments = Change {0} - Patch Set {1}: Publish Comments
 lineHeader = Line {0}:
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable.java
index c0ab584..9c78955 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable.java
@@ -493,7 +493,7 @@
       if (titleText != null) {
         setTitleText(titleText);
         return true;
-      } else if(titleWidget != null) {
+      } else if (titleWidget != null) {
         setTitleWidget(titleWidget);
         return true;
       }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CommentInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CommentInfo.java
index 9088c1c..8e73f73 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CommentInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CommentInfo.java
@@ -77,7 +77,7 @@
   public final void side(Side side) {
     sideRaw(side.toString());
   }
-  private final native void sideRaw(String s) /*-{ this.side = s }-*/;
+  private native void sideRaw(String s) /*-{ this.side = s }-*/;
 
   public final native String path() /*-{ return this.path }-*/;
   public final native String id() /*-{ return this.id }-*/;
@@ -90,7 +90,7 @@
         ? Side.valueOf(s)
         : Side.REVISION;
   }
-  private final native String sideRaw() /*-{ return this.side }-*/;
+  private native String sideRaw() /*-{ return this.side }-*/;
 
   public final Timestamp updated() {
     Timestamp r = updatedTimestamp();
@@ -103,9 +103,9 @@
     }
     return r;
   }
-  private final native String updatedRaw() /*-{ return this.updated }-*/;
-  private final native Timestamp updatedTimestamp() /*-{ return this._ts }-*/;
-  private final native void updatedTimestamp(Timestamp t) /*-{ this._ts = t }-*/;
+  private native String updatedRaw() /*-{ return this.updated }-*/;
+  private native Timestamp updatedTimestamp() /*-{ return this._ts }-*/;
+  private native void updatedTimestamp(Timestamp t) /*-{ this._ts = t }-*/;
 
   public final native AccountInfo author() /*-{ return this.author }-*/;
   public final native int line() /*-{ return this.line || 0 }-*/;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/QueryScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/QueryScreen.java
index 2b3c6ae..e7fba34 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/QueryScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/QueryScreen.java
@@ -51,7 +51,7 @@
   protected AsyncCallback<ChangeList> loadCallback() {
     return new GerritCallback<ChangeList>() {
       @Override
-      public final void onSuccess(ChangeList result) {
+      public void onSuccess(ChangeList result) {
         if (isAttached()) {
           if (result.length() == 1 && isSingleQuery(query)) {
             ChangeInfo c = result.get(0);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ReviewInput.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ReviewInput.java
index 096dbd0..a127e7f 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ReviewInput.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ReviewInput.java
@@ -19,11 +19,11 @@
 import com.google.gwt.core.client.JsArray;
 
 public class ReviewInput extends JavaScriptObject {
-  public static enum NotifyHandling {
+  public enum NotifyHandling {
     NONE, OWNER, OWNER_REVIEWERS, ALL
   }
 
-  public static enum DraftHandling {
+  public enum DraftHandling {
     DELETE, PUBLISH, KEEP, PUBLISH_ALL_REVISIONS
   }
 
@@ -42,14 +42,14 @@
   public final void notify(NotifyHandling e) {
     _notify(e.name());
   }
-  private final native void _notify(String n) /*-{ this.notify=n; }-*/;
+  private native void _notify(String n) /*-{ this.notify=n; }-*/;
 
   public final void drafts(DraftHandling e) {
     _drafts(e.name());
   }
-  private final native void _drafts(String n) /*-{ this.drafts=n; }-*/;
+  private native void _drafts(String n) /*-{ this.drafts=n; }-*/;
 
-  private final native void init() /*-{
+  private native void init() /*-{
     this.labels = {};
     this.strict_labels = true;
   }-*/;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/StarredChanges.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/StarredChanges.java
index 8750389..43b3b80 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/StarredChanges.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/StarredChanges.java
@@ -37,7 +37,7 @@
   private static final Event.Type<ChangeStarHandler> TYPE = new Event.Type<>();
 
   /** Handler that can receive notifications of a change's starred status. */
-  public static interface ChangeStarHandler {
+  public interface ChangeStarHandler {
     void onChangeStar(ChangeStarEvent event);
   }
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/SubmitInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/SubmitInfo.java
index 6d8bc30..7a24774 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/SubmitInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/SubmitInfo.java
@@ -22,7 +22,7 @@
     return Change.Status.valueOf(statusRaw());
   }
 
-  private final native String statusRaw() /*-{ return this.status; }-*/;
+  private native String statusRaw() /*-{ return this.status; }-*/;
 
   protected SubmitInfo() {
   }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/dashboards/DashboardsTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/dashboards/DashboardsTable.java
index 3b168e1..47c0359 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/dashboards/DashboardsTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/dashboards/DashboardsTable.java
@@ -84,7 +84,7 @@
     });
 
     String ref = null;
-    for(DashboardInfo d : list) {
+    for (DashboardInfo d : list) {
       if (!d.ref().equals(ref)) {
         ref = d.ref();
         insertTitleRow(table.getRowCount(), ref);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentBox.java
index 4654a3d..4fe2914 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentBox.java
@@ -24,6 +24,7 @@
 
 import net.codemirror.lib.CodeMirror;
 import net.codemirror.lib.Configuration;
+import net.codemirror.lib.Pos;
 import net.codemirror.lib.TextMarker;
 import net.codemirror.lib.TextMarker.FromTo;
 
@@ -56,7 +57,13 @@
   CommentBox(CommentGroup group, CommentRange range) {
     this.group = group;
     if (range != null) {
-      fromTo = FromTo.create(range);
+      DiffScreen screen = group.getManager().getDiffScreen();
+      int startCmLine =
+          screen.getCmLine(range.startLine() - 1, group.getSide());
+      int endCmLine = screen.getCmLine(range.endLine() - 1, group.getSide());
+      fromTo = FromTo.create(
+          Pos.create(startCmLine, range.startCharacter()),
+          Pos.create(endCmLine, range.endCharacter()));
       rangeMarker = group.getCm().markText(
           fromTo.from(),
           fromTo.to(),
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentGroup.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentGroup.java
index d48ada7..20dd883 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentGroup.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentGroup.java
@@ -63,6 +63,10 @@
     return line;
   }
 
+  DisplaySide getSide() {
+    return side;
+  }
+
   void add(PublishedBox box) {
     comments.add(box);
     comments.setVisible(true);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentManager.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentManager.java
index 4386436..7f4e446 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentManager.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentManager.java
@@ -24,6 +24,8 @@
 import com.google.gwt.core.client.JsArray;
 
 import net.codemirror.lib.CodeMirror;
+import net.codemirror.lib.Pos;
+import net.codemirror.lib.TextMarker.FromTo;
 
 import java.util.HashMap;
 import java.util.HashSet;
@@ -130,6 +132,16 @@
     return forSide;
   }
 
+  static FromTo adjustSelection(CodeMirror cm) {
+    FromTo fromTo = cm.getSelectedRange();
+    Pos to = fromTo.to();
+    if (to.ch() == 0) {
+      to.line(to.line() - 1);
+      to.ch(cm.getLine(to.line()).length());
+    }
+    return fromTo;
+  }
+
   abstract void insertNewDraft(DisplaySide side, int line);
 
   abstract Runnable newDraftCallback(final CodeMirror cm);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentRange.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentRange.java
index 9f46e9b..cd791aeb 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentRange.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentRange.java
@@ -43,7 +43,7 @@
   public final native int endLine() /*-{ return this.end_line; }-*/;
   public final native int endCharacter() /*-{ return this.end_character; }-*/;
 
-  private final native void set(int sl, int sc, int el, int ec) /*-{
+  private native void set(int sl, int sc, int el, int ec) /*-{
     this.start_line = sl;
     this.start_character = sc;
     this.end_line = el;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentsCollections.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentsCollections.java
index b23a8cf..83f74a3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentsCollections.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentsCollections.java
@@ -29,17 +29,23 @@
 
 /** Collection of published and draft comments loaded from the server. */
 class CommentsCollections {
-  private String path;
-
+  private final String path;
+  private final PatchSet.Id base;
+  private final PatchSet.Id revision;
+  private NativeMap<JsArray<CommentInfo>> publishedBaseAll;
+  private NativeMap<JsArray<CommentInfo>> publishedRevisionAll;
   JsArray<CommentInfo> publishedBase;
   JsArray<CommentInfo> publishedRevision;
   JsArray<CommentInfo> draftsBase;
   JsArray<CommentInfo> draftsRevision;
 
-  void load(PatchSet.Id base, PatchSet.Id revision, String path,
-      CallbackGroup group) {
+  CommentsCollections(PatchSet.Id base, PatchSet.Id revision, String path) {
     this.path = path;
+    this.base = base;
+    this.revision = revision;
+  }
 
+  void load(CallbackGroup group) {
     if (base != null) {
       CommentApi.comments(base, group.add(publishedBase()));
     }
@@ -53,10 +59,25 @@
     }
   }
 
+  boolean hasCommentForPath(String filePath) {
+    if (base != null) {
+      JsArray<CommentInfo> forBase = publishedBaseAll.get(filePath);
+      if (forBase != null && forBase.length() > 0) {
+        return true;
+      }
+    }
+    JsArray<CommentInfo> forRevision = publishedRevisionAll.get(filePath);
+    if (forRevision != null && forRevision.length() > 0) {
+      return true;
+    }
+    return false;
+  }
+
   private AsyncCallback<NativeMap<JsArray<CommentInfo>>> publishedBase() {
     return new AsyncCallback<NativeMap<JsArray<CommentInfo>>>() {
       @Override
       public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
+        publishedBaseAll = result;
         publishedBase = sort(result.get(path));
       }
 
@@ -70,6 +91,7 @@
     return new AsyncCallback<NativeMap<JsArray<CommentInfo>>>() {
       @Override
       public void onSuccess(NativeMap<JsArray<CommentInfo>> result) {
+        publishedRevisionAll = result;
         publishedRevision = sort(result.get(path));
       }
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffInfo.java
index 82dad3f..bf141a2 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffInfo.java
@@ -45,7 +45,7 @@
     return filterWebLinks(DiffView.UNIFIED_DIFF);
   }
 
-  private final List<WebLinkInfo> filterWebLinks(DiffView diffView) {
+  private List<WebLinkInfo> filterWebLinks(DiffView diffView) {
     List<WebLinkInfo> filteredDiffWebLinks = new LinkedList<>();
     List<DiffWebLinkInfo> allDiffWebLinks = Natives.asList(webLinks());
     if (allDiffWebLinks != null) {
@@ -66,7 +66,7 @@
   public final ChangeType changeType() {
     return ChangeType.valueOf(changeTypeRaw());
   }
-  private final native String changeTypeRaw()
+  private native String changeTypeRaw()
   /*-{ return this.change_type }-*/;
 
   public final IntraLineStatus intralineStatus() {
@@ -75,7 +75,7 @@
         ? IntraLineStatus.valueOf(s)
         : IntraLineStatus.OFF;
   }
-  private final native String intralineStatusRaw()
+  private native String intralineStatusRaw()
   /*-{ return this.intraline_status }-*/;
 
   public final boolean hasSkip() {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffScreen.java
index cf0f9aa..01d6b16 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffScreen.java
@@ -138,7 +138,8 @@
     prefs = DiffPreferences.create(Gerrit.getDiffPreferences());
     handlers = new ArrayList<>(6);
     keysNavigation = new KeyCommandSet(Gerrit.C.sectionNavigation());
-    header = new Header(keysNavigation, base, revision, path, diffScreenType);
+    header = new Header(
+        keysNavigation, base, revision, path, diffScreenType, prefs);
   }
 
   @Override
@@ -208,8 +209,9 @@
           }));
     }
 
-    final CommentsCollections comments = new CommentsCollections();
-    comments.load(base, revision, path, group2);
+    final CommentsCollections comments =
+        new CommentsCollections(base, revision, path);
+    comments.load(group2);
 
     RestApi call = ChangeApi.detail(changeId.get());
     ChangeList.addOptions(call, EnumSet.of(
@@ -477,8 +479,8 @@
         new NoOpKeyCommand(0, 'j', PatchUtil.C.lineNext()),
         new NoOpKeyCommand(0, 'k', PatchUtil.C.linePrev()));
     keysNavigation.add(
-        new NoOpKeyCommand(0, 'n', PatchUtil.C.chunkNext2()),
-        new NoOpKeyCommand(0, 'p', PatchUtil.C.chunkPrev2()));
+        new NoOpKeyCommand(0, 'n', PatchUtil.C.chunkNext()),
+        new NoOpKeyCommand(0, 'p', PatchUtil.C.chunkPrev()));
     keysNavigation.add(
         new NoOpKeyCommand(KeyCommand.M_SHIFT, 'n', PatchUtil.C.commentNext()),
         new NoOpKeyCommand(KeyCommand.M_SHIFT, 'p', PatchUtil.C.commentPrev()));
@@ -932,6 +934,8 @@
 
   abstract DiffTable getDiffTable();
 
+  abstract int getCmLine(int line, DisplaySide side);
+
   LineOnOtherInfo lineOnOther(DisplaySide side, int line) {
     return getChunkManager().getLineMapper().lineOnOther(side, line);
   }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.java
index a554df6..e7dabbb 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.java
@@ -16,6 +16,7 @@
 
 import com.google.gerrit.client.Dispatcher;
 import com.google.gerrit.client.Gerrit;
+import com.google.gerrit.client.account.DiffPreferences;
 import com.google.gerrit.client.changes.ChangeApi;
 import com.google.gerrit.client.changes.ReviewInfo;
 import com.google.gerrit.client.changes.Util;
@@ -35,6 +36,7 @@
 import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.extensions.client.GeneralPreferencesInfo.DiffView;
 import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.Patch.ChangeType;
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.core.client.JsArray;
@@ -68,7 +70,7 @@
     Resources.I.style().ensureInjected();
   }
 
-  private static enum ReviewedState {
+  private enum ReviewedState {
     AUTO_REVIEW, LOADED
   }
 
@@ -91,20 +93,23 @@
   private final PatchSet.Id patchSetId;
   private final String path;
   private final DiffView diffScreenType;
+  private final DiffPreferences prefs;
   private boolean hasPrev;
   private boolean hasNext;
   private String nextPath;
+  private JsArray<FileInfo> files;
   private PreferencesAction prefsAction;
   private ReviewedState reviewedState;
 
   Header(KeyCommandSet keys, PatchSet.Id base, PatchSet.Id patchSetId,
-      String path, DiffView diffSreenType) {
+      String path, DiffView diffSreenType, DiffPreferences prefs) {
     initWidget(uiBinder.createAndBindUi(this));
     this.keys = keys;
     this.base = base;
     this.patchSetId = patchSetId;
     this.path = path;
     this.diffScreenType = diffSreenType;
+    this.prefs = prefs;
 
     if (!Gerrit.isSignedIn()) {
       reviewed.getElement().getStyle().setVisibility(Visibility.HIDDEN);
@@ -141,34 +146,27 @@
     return b;
   }
 
+  private int findCurrentFileIndex(JsArray<FileInfo> files) {
+    int currIndex = 0;
+    for (int i = 0; i < files.length(); i++) {
+      if (path.equals(files.get(i).path())) {
+        currIndex = i;
+        break;
+      }
+    }
+    return currIndex;
+  }
+
   @Override
   protected void onLoad() {
     DiffApi.list(patchSetId, base, new GerritCallback<NativeMap<FileInfo>>() {
       @Override
       public void onSuccess(NativeMap<FileInfo> result) {
-        JsArray<FileInfo> files = result.values();
+        files = result.values();
         FileInfo.sortFileInfoByPath(files);
         fileNumber.setInnerText(
             Integer.toString(Natives.asList(files).indexOf(result.get(path)) + 1));
         fileCount.setInnerText(Integer.toString(files.length()));
-        int index = 0; // TODO: Maybe use patchIndex.
-        for (int i = 0; i < files.length(); i++) {
-          if (path.equals(files.get(i).path())) {
-            index = i;
-            break;
-          }
-        }
-        FileInfo nextInfo = index == files.length() - 1
-            ? null
-            : files.get(index + 1);
-        KeyCommand p = setupNav(prev, '[', PatchUtil.C.previousFileHelp(),
-            index == 0 ? null : files.get(index - 1));
-        KeyCommand n = setupNav(next, ']', PatchUtil.C.nextFileHelp(),
-            nextInfo);
-        if (p != null && n != null) {
-          keys.pair(p, n);
-        }
-        nextPath = nextInfo != null ? nextInfo.path() : null;
       }
     });
 
@@ -302,6 +300,44 @@
     }
   }
 
+  private boolean shouldSkipFile(FileInfo curr, CommentsCollections comments) {
+    return prefs.skipDeleted() && ChangeType.DELETED.matches(curr.status())
+        || prefs.skipUnchanged() && ChangeType.RENAMED.matches(curr.status())
+        || prefs.skipUncommented() && !comments.hasCommentForPath(curr.path());
+  }
+
+  void setupPrevNextFiles(CommentsCollections comments) {
+    FileInfo prevInfo = null;
+    FileInfo nextInfo = null;
+    int currIndex = findCurrentFileIndex(files);
+    for (int i = currIndex - 1; i >= 0; i--) {
+      FileInfo curr = files.get(i);
+      if (shouldSkipFile(curr, comments)) {
+        continue;
+      } else {
+        prevInfo = curr;
+        break;
+      }
+    }
+    for (int i = currIndex + 1; i < files.length(); i++) {
+      FileInfo curr = files.get(i);
+      if (shouldSkipFile(curr, comments)) {
+        continue;
+      } else {
+        nextInfo = curr;
+        break;
+      }
+    }
+    KeyCommand p = setupNav(prev, '[', PatchUtil.C.previousFileHelp(),
+        prevInfo);
+    KeyCommand n = setupNav(next, ']', PatchUtil.C.nextFileHelp(),
+        nextInfo);
+    if (p != null && n != null) {
+      keys.pair(p, n);
+    }
+    nextPath = nextInfo != null ? nextInfo.path() : null;
+  }
+
   Runnable toggleReviewed() {
     return new Runnable() {
       @Override
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.java
index 0d856eb..cc3c004 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.java
@@ -102,6 +102,9 @@
   @UiField ToggleButton expandAllComments;
   @UiField ToggleButton renderEntireFile;
   @UiField ToggleButton matchBrackets;
+  @UiField ToggleButton skipDeleted;
+  @UiField ToggleButton skipUnchanged;
+  @UiField ToggleButton skipUncommented;
   @UiField ListBox theme;
   @UiField Element modeLabel;
   @UiField ListBox mode;
@@ -194,6 +197,9 @@
     manualReview.setValue(prefs.manualReview());
     expandAllComments.setValue(prefs.expandAllComments());
     matchBrackets.setValue(prefs.matchBrackets());
+    skipDeleted.setValue(!prefs.skipDeleted());
+    skipUnchanged.setValue(!prefs.skipUnchanged());
+    skipUncommented.setValue(!prefs.skipUncommented());
     setTheme(prefs.theme());
 
     if (view == null || view.canRenderEntireFile(prefs)) {
@@ -497,6 +503,24 @@
         prefs.matchBrackets());
   }
 
+  @UiHandler("skipDeleted")
+  void onSkipDeleted(ValueChangeEvent<Boolean> e) {
+    prefs.skipDeleted(!e.getValue());
+    // TODO: Update the navigation links on the current DiffScreen
+  }
+
+  @UiHandler("skipUnchanged")
+  void onSkipUnchanged(ValueChangeEvent<Boolean> e) {
+    prefs.skipUnchanged(!e.getValue());
+    // TODO: Update the navigation links on the current DiffScreen
+  }
+
+  @UiHandler("skipUncommented")
+  void onSkipUncommented(ValueChangeEvent<Boolean> e) {
+    prefs.skipUncommented(!e.getValue());
+    // TODO: Update the navigation links on the current DiffScreen
+  }
+
   @UiHandler("theme")
   void onTheme(@SuppressWarnings("unused") ChangeEvent e) {
     final Theme newTheme = getSelectedTheme();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.ui.xml
index a2202ab..0a5e6a2 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.ui.xml
@@ -297,6 +297,27 @@
         </g:ToggleButton></td>
       </tr>
       <tr>
+        <th><ui:msg>Skip Deleted Files</ui:msg></th>
+        <td><g:ToggleButton ui:field='skipDeleted'>
+          <g:upFace><ui:msg>Yes</ui:msg></g:upFace>
+          <g:downFace><ui:msg>No</ui:msg></g:downFace>
+        </g:ToggleButton></td>
+      </tr>
+      <tr>
+        <th><ui:msg>Skip Unchanged Files</ui:msg></th>
+        <td><g:ToggleButton ui:field='skipUnchanged'>
+          <g:upFace><ui:msg>Yes</ui:msg></g:upFace>
+          <g:downFace><ui:msg>No</ui:msg></g:downFace>
+        </g:ToggleButton></td>
+      </tr>
+      <tr>
+        <th><ui:msg>Skip Uncommented Files</ui:msg></th>
+        <td><g:ToggleButton ui:field='skipUncommented'>
+          <g:upFace><ui:msg>Yes</ui:msg></g:upFace>
+          <g:downFace><ui:msg>No</ui:msg></g:downFace>
+        </g:ToggleButton></td>
+      </tr>
+      <tr>
         <td></td>
         <td>
           <g:Button ui:field='apply' styleName='{style.apply}'>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PublishedBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PublishedBox.java
index cfa6e00..e497e8b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PublishedBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PublishedBox.java
@@ -46,7 +46,7 @@
   interface Binder extends UiBinder<HTMLPanel, PublishedBox> {}
   private static final Binder uiBinder = GWT.create(Binder.class);
 
-  static interface Style extends CssResource {
+  interface Style extends CssResource {
     String closed();
   }
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Resources.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Resources.java
index 0359df3..2723374 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Resources.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Resources.java
@@ -20,7 +20,7 @@
 
 /** Resources used by diff. */
 interface Resources extends ClientBundle {
-  static final Resources I = GWT.create(Resources.class);
+  Resources I = GWT.create(Resources.class);
 
   @Source("CommentBox.css") CommentBox.Style style();
   @Source("Scrollbar.css") Scrollbar.Style scrollbarStyle();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide.java
index 931636f..fa7e0e4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide.java
@@ -94,6 +94,7 @@
             getChangeStatus().isOpen());
         setTheme(result.getTheme());
         display(comments);
+        header.setupPrevNextFiles(comments);
       }
     };
   }
@@ -111,7 +112,7 @@
         cmB.refresh();
       }
     });
-    setLineLength(Patch.COMMIT_MSG.equals(prefs) ? 72 : prefs.lineLength());
+    setLineLength(Patch.COMMIT_MSG.equals(path) ? 72 : prefs.lineLength());
     diffTable.refresh();
 
     if (getStartLine() == 0) {
@@ -309,6 +310,11 @@
   }
 
   @Override
+  int getCmLine(int line, DisplaySide side) {
+    return line;
+  }
+
+  @Override
   Runnable updateActiveLine(final CodeMirror cm) {
     final CodeMirror other = otherCm(cm);
     return new Runnable() {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySideChunkManager.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySideChunkManager.java
index dcbcb67..cbbafad 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySideChunkManager.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySideChunkManager.java
@@ -45,7 +45,7 @@
   private static double guessedLineHeightPx = 15;
   private static final JavaScriptObject focusA = initOnClick(A);
   private static final JavaScriptObject focusB = initOnClick(B);
-  private static final native JavaScriptObject initOnClick(DisplaySide s) /*-{
+  private static native JavaScriptObject initOnClick(DisplaySide s) /*-{
     return $entry(function(e){
       @com.google.gerrit.client.diff.SideBySideChunkManager::focus(
         Lcom/google/gwt/dom/client/NativeEvent;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySideCommentManager.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySideCommentManager.java
index 88e431f..cf9dd0f 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySideCommentManager.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySideCommentManager.java
@@ -333,18 +333,13 @@
   private void newDraft(CodeMirror cm) {
     int line = cm.getLineNumber(cm.extras().activeLine()) + 1;
     if (cm.somethingSelected()) {
-      FromTo fromTo = cm.getSelectedRange();
-      Pos end = fromTo.to();
-      if (end.ch() == 0) {
-        end.line(end.line() - 1);
-        end.ch(cm.getLine(end.line()).length());
-      }
-
+      FromTo fromTo = adjustSelection(cm);
       addDraftBox(cm.side(), CommentInfo.create(
               getPath(),
               getStoredSideFromDisplaySide(cm.side()),
               line,
               CommentRange.create(fromTo))).setEdit(true);
+      cm.setCursor(fromTo.to());
       cm.setSelection(cm.getCursor());
     } else {
       insertNewDraft(cm.side(), line);
@@ -357,7 +352,8 @@
       return w;
     }
 
-    int lineA, lineB;
+    int lineA;
+    int lineB;
     if (line == 0) {
       lineA = lineB = 0;
     } else if (side == DisplaySide.A) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySideSkipBar.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySideSkipBar.java
index 5020fed..c4587a0 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySideSkipBar.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySideSkipBar.java
@@ -44,9 +44,9 @@
     String noExpand();
   }
 
-  @UiField(provided=true) Anchor skipNum;
-  @UiField(provided=true) Anchor upArrow;
-  @UiField(provided=true) Anchor downArrow;
+  @UiField(provided = true) Anchor skipNum;
+  @UiField(provided = true) Anchor upArrow;
+  @UiField(provided = true) Anchor downArrow;
   @UiField SkipBarStyle style;
 
   private final SideBySideSkipManager manager;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Unified.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Unified.java
index 904d47d..6b48f15 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Unified.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Unified.java
@@ -18,7 +18,7 @@
 
 import com.google.gerrit.client.Dispatcher;
 import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.client.diff.UnifiedChunkManager.LineSidePair;
+import com.google.gerrit.client.diff.UnifiedChunkManager.LineRegionInfo;
 import com.google.gerrit.client.patches.PatchUtil;
 import com.google.gerrit.client.projects.ConfigInfoCache;
 import com.google.gerrit.client.rpc.ScreenLoadCallback;
@@ -98,6 +98,7 @@
             getChangeStatus().isOpen());
         setTheme(result.getTheme());
         display(comments);
+        header.setupPrevNextFiles(comments);
       }
     };
   }
@@ -362,12 +363,13 @@
     return cm;
   }
 
+  @Override
   int getCmLine(int line, DisplaySide side) {
     return chunkManager.getCmLine(line, side);
   }
 
-  LineSidePair getLineSidePairFromCmLine(int cmLine) {
-    return chunkManager.getLineSidePairFromCmLine(cmLine);
+  LineRegionInfo getLineRegionInfoFromCmLine(int cmLine) {
+    return chunkManager.getLineRegionInfoFromCmLine(cmLine);
   }
 
   @Override
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/UnifiedChunkManager.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/UnifiedChunkManager.java
index 866f0f7..1e6ed0c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/UnifiedChunkManager.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/UnifiedChunkManager.java
@@ -38,7 +38,7 @@
 /** Colors modified regions for {@link Unified}. */
 class UnifiedChunkManager extends ChunkManager {
   private static final JavaScriptObject focus = initOnClick();
-  private static final native JavaScriptObject initOnClick() /*-{
+  private static native JavaScriptObject initOnClick() /*-{
     return $entry(function(e){
       @com.google.gerrit.client.diff.UnifiedChunkManager::focus(
         Lcom/google/gwt/dom/client/NativeEvent;)(e)
@@ -279,52 +279,72 @@
     }
   }
 
-  LineSidePair getLineSidePairFromCmLine(int cmLine) {
+  LineRegionInfo getLineRegionInfoFromCmLine(int cmLine) {
     int res =
         Collections.binarySearch(chunks,
             new UnifiedDiffChunkInfo(
                 DisplaySide.A, 0, 0, cmLine, false), // Dummy DiffChunkInfo
             getDiffChunkComparatorCmLine());
-    if (res >= 0) {
+    if (res >= 0) {  // The line is right at the start of a diff chunk.
       UnifiedDiffChunkInfo info = chunks.get(res);
-      return new LineSidePair(info.getStart(), info.getSide());
-    } else {  // The line might be within a DiffChunk
+      return new LineRegionInfo(
+          info.getStart(), displaySideToRegionType(info.getSide()));
+    } else {  // The line might be within or after a diff chunk.
       res = -res - 1;
       if (res > 0) {
         UnifiedDiffChunkInfo info = chunks.get(res - 1);
         int lineOnInfoSide = info.getStart() + cmLine - info.getCmLine();
-        if (lineOnInfoSide > info.getEnd()
-            && info.getSide() == DisplaySide.A) {
-          // For the common region after a deletion chunk, return the line and
-          // side info on side B
-          return new LineSidePair(
-              getLineMapper().lineOnOther(DisplaySide.A, lineOnInfoSide)
-                  .getLine(), DisplaySide.B);
-        } else {
-          return new LineSidePair(lineOnInfoSide, info.getSide());
+        if (lineOnInfoSide > info.getEnd()) { // After a diff chunk
+          if (info.getSide() == DisplaySide.A) {
+            // For the common region after a deletion chunk, associate the line
+            // on side B with a common region.
+            return new LineRegionInfo(
+                getLineMapper().lineOnOther(DisplaySide.A, lineOnInfoSide)
+                    .getLine(), RegionType.COMMON);
+          } else {
+            return new LineRegionInfo(lineOnInfoSide, RegionType.COMMON);
+          }
+        } else { // Within a diff chunk
+          return new LineRegionInfo(
+              lineOnInfoSide, displaySideToRegionType(info.getSide()));
         }
       } else {
-        // Always return side B
-        return new LineSidePair(cmLine, DisplaySide.B);
+        // The line is before any diff chunk, so it always equals cmLine and
+        // belongs to a common region.
+        return new LineRegionInfo(cmLine, RegionType.COMMON);
       }
     }
   }
 
-  static class LineSidePair {
-    private int line;
-    private DisplaySide side;
+  enum RegionType {
+    INSERT, DELETE, COMMON,
+  }
 
-    LineSidePair(int line, DisplaySide side) {
+  private static RegionType displaySideToRegionType(DisplaySide side) {
+    return side == DisplaySide.A ? RegionType.DELETE : RegionType.INSERT;
+  }
+
+  /**
+   * Helper class to associate a line in the original file with the type of the
+   * region it belongs to.
+   *
+   * @field line The 0-based line number in the original file. Note that this
+   *     might be different from the line number shown in CodeMirror.
+   * @field type The type of the region the line belongs to. Can be INSERT,
+   *     DELETE or COMMON.
+   */
+  static class LineRegionInfo {
+    final int line;
+    final RegionType type;
+
+    LineRegionInfo(int line, RegionType type) {
       this.line = line;
-      this.side = side;
-    }
-
-    int getLine() {
-      return line;
+      this.type = type;
     }
 
     DisplaySide getSide() {
-      return side;
+      // Always return DisplaySide.B for INSERT or COMMON
+      return type == RegionType.DELETE ? DisplaySide.A : DisplaySide.B;
     }
   }
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/UnifiedCommentManager.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/UnifiedCommentManager.java
index 9038fb4..411b64f 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/UnifiedCommentManager.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/UnifiedCommentManager.java
@@ -16,7 +16,9 @@
 
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.changes.CommentInfo;
-import com.google.gerrit.client.diff.UnifiedChunkManager.LineSidePair;
+import com.google.gerrit.client.diff.LineMapper.LineOnOtherInfo;
+import com.google.gerrit.client.diff.UnifiedChunkManager.LineRegionInfo;
+import com.google.gerrit.client.diff.UnifiedChunkManager.RegionType;
 import com.google.gerrit.client.patches.SkippedLine;
 import com.google.gerrit.client.rpc.Natives;
 import com.google.gerrit.client.ui.CommentLinkProcessor;
@@ -26,6 +28,7 @@
 import net.codemirror.lib.CodeMirror;
 import net.codemirror.lib.CodeMirror.LineHandle;
 import net.codemirror.lib.Pos;
+import net.codemirror.lib.TextMarker.FromTo;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -179,10 +182,10 @@
         ((PublishedBox)last).doReply();
       }
     } else {
-      LineSidePair pair = host.getLineSidePairFromCmLine(cmLinePlusOne - 1);
-      int line = pair.getLine();
-      if (pair.getSide() != side) {
-        line = host.lineOnOther(pair.getSide(), line).getLine();
+      LineRegionInfo info = host.getLineRegionInfoFromCmLine(cmLinePlusOne - 1);
+      int line = info.line;
+      if (info.getSide() != side) {
+        line = host.lineOnOther(info.getSide(), line).getLine();
       }
       addDraftBox(side, CommentInfo.create(
           getPath(),
@@ -335,13 +338,68 @@
   }
 
   private void newDraft(CodeMirror cm) {
-    int cmLine = cm.getLineNumber(cm.extras().activeLine());
-    LineSidePair pair = host.getLineSidePairFromCmLine(cmLine);
-    DisplaySide side = pair.getSide();
     if (cm.somethingSelected()) {
-      // TODO: Handle range comment
+      FromTo fromTo = adjustSelection(cm);
+      Pos from = fromTo.from();
+      Pos to = fromTo.to();
+      UnifiedChunkManager manager = host.getChunkManager();
+      LineRegionInfo fromInfo =
+          host.getLineRegionInfoFromCmLine(from.line());
+      LineRegionInfo toInfo =
+          host.getLineRegionInfoFromCmLine(to.line());
+      DisplaySide side = toInfo.getSide();
+
+      // Handle special cases in selections that span multiple regions. Force
+      // start line to be on the same side as the end line.
+      if ((fromInfo.type == RegionType.INSERT
+          || fromInfo.type == RegionType.COMMON)
+          && toInfo.type == RegionType.DELETE) {
+        LineOnOtherInfo infoOnSideA = manager.getLineMapper()
+            .lineOnOther(DisplaySide.B, fromInfo.line);
+        int startLineOnSideA = infoOnSideA.getLine();
+        if (infoOnSideA.isAligned()) {
+          from.line(startLineOnSideA);
+        } else {
+          from.line(startLineOnSideA + 1);
+        }
+        from.ch(0);
+        to.line(toInfo.line);
+      } else if (fromInfo.type == RegionType.DELETE
+          && toInfo.type == RegionType.INSERT) {
+        LineOnOtherInfo infoOnSideB = manager.getLineMapper()
+            .lineOnOther(DisplaySide.A, fromInfo.line);
+        int startLineOnSideB = infoOnSideB.getLine();
+        if (infoOnSideB.isAligned()) {
+          from.line(startLineOnSideB);
+        } else {
+          from.line(startLineOnSideB + 1);
+        }
+        from.ch(0);
+        to.line(toInfo.line);
+      } else if (fromInfo.type == RegionType.DELETE
+          && toInfo.type == RegionType.COMMON) {
+        int toLineOnSideA = manager.getLineMapper()
+            .lineOnOther(DisplaySide.B, toInfo.line).getLine();
+        from.line(fromInfo.line);
+        // Force the end line to be on the same side as the start line.
+        to.line(toLineOnSideA);
+        side = DisplaySide.A;
+      } else { // Common case
+        from.line(fromInfo.line);
+        to.line(toInfo.line);
+      }
+
+      addDraftBox(side, CommentInfo.create(
+              getPath(),
+              getStoredSideFromDisplaySide(side),
+              to.line() + 1,
+              CommentRange.create(fromTo))).setEdit(true);
+      cm.setCursor(Pos.create(host.getCmLine(to.line(), side), to.ch()));
+      cm.setSelection(cm.getCursor());
     } else {
-      insertNewDraft(side, cmLine + 1);
+      int cmLine = cm.getLineNumber(cm.extras().activeLine());
+      LineRegionInfo info = host.getLineRegionInfoFromCmLine(cmLine);
+      insertNewDraft(info.getSide(), cmLine + 1);
     }
   }
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/UnifiedSkipBar.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/UnifiedSkipBar.java
index 4cbf9b0..2c26774 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/UnifiedSkipBar.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/UnifiedSkipBar.java
@@ -44,9 +44,9 @@
     String noExpand();
   }
 
-  @UiField(provided=true) Anchor skipNum;
-  @UiField(provided=true) Anchor upArrow;
-  @UiField(provided=true) Anchor downArrow;
+  @UiField(provided = true) Anchor skipNum;
+  @UiField(provided = true) Anchor upArrow;
+  @UiField(provided = true) Anchor downArrow;
   @UiField SkipBarStyle style;
 
   private final UnifiedSkipManager manager;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/DocTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/DocTable.java
index b57cdac..0c5be8e 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/DocTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/DocTable.java
@@ -28,10 +28,10 @@
 class DocTable extends NavigationTable<DocInfo> {
   private static final int C_TITLE = 1;
 
-  private int rows = 0;
-  private int dataBeginRow = 0;
+  private int rows;
+  private int dataBeginRow;
 
-  public DocTable() {
+  DocTable() {
     super(Util.C.docItemHelp());
 
     table.setText(0, C_TITLE, Util.C.docTableColumnTitle());
@@ -117,7 +117,7 @@
   }
 
   public static class DocLink extends Anchor {
-    public DocLink(DocInfo d) {
+    DocLink(DocInfo d) {
       super(com.google.gerrit.client.changes.Util.cropSubject(d.title()));
       setHref(d.getFullUrl());
     }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditConstants.java
index e95fdfc..8dc4137 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditConstants.java
@@ -18,7 +18,7 @@
 import com.google.gwt.i18n.client.Constants;
 
 interface EditConstants extends Constants {
-  static final EditConstants I = GWT.create(EditConstants.class);
+  EditConstants I = GWT.create(EditConstants.class);
 
   String closeUnsavedChanges();
   String cancelUnsavedChanges();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditPreferencesBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditPreferencesBox.java
index edfb15e..b9bd7f4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditPreferencesBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditPreferencesBox.java
@@ -60,6 +60,7 @@
   @UiField Anchor close;
   @UiField NpIntTextBox tabWidth;
   @UiField NpIntTextBox lineLength;
+  @UiField NpIntTextBox indentUnit;
   @UiField NpIntTextBox cursorBlinkRate;
   @UiField ToggleButton topMenu;
   @UiField ToggleButton syntaxHighlighting;
@@ -94,6 +95,7 @@
 
     tabWidth.setIntValue(prefs.tabSize());
     lineLength.setIntValue(prefs.lineLength());
+    indentUnit.setIntValue(prefs.indentUnit());
     cursorBlinkRate.setIntValue(prefs.cursorBlinkRate());
     topMenu.setValue(!prefs.hideTopMenu());
     syntaxHighlighting.setValue(prefs.syntaxHighlighting());
@@ -128,6 +130,17 @@
     }
   }
 
+  @UiHandler("indentUnit")
+  void onIndentUnit(ValueChangeEvent<String> e) {
+    String v = e.getValue();
+    if (v != null && v.length() > 0) {
+      prefs.indentUnit(Math.max(0, Integer.parseInt(v)));
+      if (view != null) {
+        view.setIndentUnit(prefs.indentUnit());
+      }
+    }
+  }
+
   @UiHandler("cursorBlinkRate")
   void onCursoBlinkRate(ValueChangeEvent<String> e) {
     String v = e.getValue();
@@ -309,6 +322,9 @@
         KeyMapType.EMACS.name().toLowerCase(),
         KeyMapType.EMACS.name());
     keyMap.addItem(
+        KeyMapType.SUBLIME.name().toLowerCase(),
+        KeyMapType.SUBLIME.name());
+    keyMap.addItem(
         KeyMapType.VIM.name().toLowerCase(),
         KeyMapType.VIM.name());
   }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditPreferencesBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditPreferencesBox.ui.xml
index ec8ad39..c07ac56 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditPreferencesBox.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditPreferencesBox.ui.xml
@@ -184,6 +184,12 @@
             alignment='RIGHT'/></td>
       </tr>
       <tr>
+        <th><ui:msg>Indent Unit</ui:msg></th>
+        <td><x:NpIntTextBox ui:field='indentUnit'
+            visibleLength='4'
+            alignment='RIGHT'/></td>
+      </tr>
+      <tr>
         <th><ui:msg>Cursor Blink Rate</ui:msg></th>
         <td><x:NpIntTextBox ui:field='cursorBlinkRate'
             visibleLength='4'
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java
index 5799433..30866ab 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java
@@ -258,20 +258,7 @@
     return new Runnable() {
       @Override
       public void run() {
-        String n = Window.prompt(EditConstants.I.gotoLineNumber(), "");
-        if (n != null) {
-          try {
-            int line = Integer.parseInt(n);
-            line--;
-            if (line >= 0) {
-              cm.scrollToLine(line);
-            }
-          } catch (NumberFormatException e) {
-            // ignore non valid numbers
-            // We don't want to popup another ugly dialog just to say
-            // "The number you've provided is invalid, try again"
-          }
-        }
+        cm.execCommand("jumpToLine");
       }
     };
   }
@@ -366,6 +353,11 @@
         Patch.COMMIT_MSG.equals(path) ? 72 : length);
   }
 
+  void setIndentUnit(int indent) {
+    cm.setOption("indentUnit",
+        Patch.COMMIT_MSG.equals(path) ? 2 : indent);
+  }
+
   void setShowLineNumbers(boolean show) {
     cm.setOption("lineNumbers", show);
   }
@@ -421,21 +413,22 @@
       }
     }
     cm = CodeMirror.create(editor, Configuration.create()
-        .set("value", content)
-        .set("readOnly", false)
+        .set("autoCloseBrackets", prefs.autoCloseBrackets())
         .set("cursorBlinkRate", prefs.cursorBlinkRate())
         .set("cursorHeight", 0.85)
+        .set("indentUnit", prefs.indentUnit())
+        .set("keyMap", prefs.keyMapType().name().toLowerCase())
         .set("lineNumbers", prefs.hideLineNumbers())
-        .set("tabSize", prefs.tabSize())
         .set("lineWrapping", false)
         .set("matchBrackets", prefs.matchBrackets())
-        .set("autoCloseBrackets", prefs.autoCloseBrackets())
+        .set("mode", mode != null ? mode.mode() : null)
+        .set("readOnly", false)
         .set("scrollbarStyle", "overlay")
-        .set("styleSelectedText", true)
         .set("showTrailingSpace", prefs.showWhitespaceErrors())
-        .set("keyMap", prefs.keyMapType().name().toLowerCase())
+        .set("styleSelectedText", true)
+        .set("tabSize", prefs.tabSize())
         .set("theme", prefs.theme().name().toLowerCase())
-        .set("mode", mode != null ? mode.mode() : null));
+        .set("value", content));
 
     CodeMirror.addCommand("save", new CommandRunner() {
       @Override
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupAuditEventInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupAuditEventInfo.java
index f62ae22..ed41b65 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupAuditEventInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupAuditEventInfo.java
@@ -37,8 +37,8 @@
   public final native AccountInfo memberAsUser() /*-{ return this.member; }-*/;
   public final native GroupInfo memberAsGroup() /*-{ return this.member; }-*/;
 
-  private final native String dateRaw() /*-{ return this.date; }-*/;
-  private final native String typeRaw() /*-{ return this.type; }-*/;
+  private native String dateRaw() /*-{ return this.date; }-*/;
+  private native String typeRaw() /*-{ return this.type; }-*/;
 
   protected GroupAuditEventInfo() {
   }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupInfo.java
index 6142e5b..c3fd4ed 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupInfo.java
@@ -33,9 +33,9 @@
   public final native JsArray<AccountInfo> members() /*-{ return this.members; }-*/;
   public final native JsArray<GroupInfo> includes() /*-{ return this.includes; }-*/;
 
-  private final native int group_id() /*-{ return this.group_id; }-*/;
-  private final native String owner_id() /*-{ return this.owner_id; }-*/;
-  private final native void owner_id(String o) /*-{ if(o)this.owner_id=o; }-*/;
+  private native int group_id() /*-{ return this.group_id; }-*/;
+  private native String owner_id() /*-{ return this.owner_id; }-*/;
+  private native void owner_id(String o) /*-{ if(o)this.owner_id=o; }-*/;
 
   public final AccountGroup.UUID getOwnerUUID() {
     String owner = owner_id();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AbstractPatchContentTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AbstractPatchContentTable.java
deleted file mode 100644
index 5b9203a..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AbstractPatchContentTable.java
+++ /dev/null
@@ -1,970 +0,0 @@
-// Copyright (C) 2008 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.client.patches;
-
-import com.google.gerrit.client.FormatUtil;
-import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.client.changes.CommentApi;
-import com.google.gerrit.client.changes.CommentInfo;
-import com.google.gerrit.client.info.AccountInfo;
-import com.google.gerrit.client.rpc.GerritCallback;
-import com.google.gerrit.client.ui.CommentLinkProcessor;
-import com.google.gerrit.client.ui.CommentPanel;
-import com.google.gerrit.client.ui.NavigationTable;
-import com.google.gerrit.client.ui.NeedsSignInKeyCommand;
-import com.google.gerrit.common.data.AccountInfoCache;
-import com.google.gerrit.common.data.CommentDetail;
-import com.google.gerrit.common.data.PatchScript;
-import com.google.gerrit.common.data.PatchSetDetail;
-import com.google.gerrit.extensions.client.DiffPreferencesInfo;
-import com.google.gerrit.prettify.client.ClientSideFormatter;
-import com.google.gerrit.prettify.client.PrettyFormatter;
-import com.google.gerrit.prettify.client.SparseHtmlFile;
-import com.google.gerrit.prettify.common.SparseFileContent;
-import com.google.gerrit.reviewdb.client.Patch;
-import com.google.gerrit.reviewdb.client.PatchLineComment;
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.dom.client.Element;
-import com.google.gwt.event.dom.client.BlurEvent;
-import com.google.gwt.event.dom.client.BlurHandler;
-import com.google.gwt.event.dom.client.ClickEvent;
-import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.event.dom.client.DoubleClickEvent;
-import com.google.gwt.event.dom.client.DoubleClickHandler;
-import com.google.gwt.event.dom.client.FocusEvent;
-import com.google.gwt.event.dom.client.FocusHandler;
-import com.google.gwt.event.dom.client.KeyCodes;
-import com.google.gwt.event.dom.client.KeyPressEvent;
-import com.google.gwt.event.shared.HandlerRegistration;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.History;
-import com.google.gwt.user.client.ui.Button;
-import com.google.gwt.user.client.ui.Focusable;
-import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
-import com.google.gwt.user.client.ui.Image;
-import com.google.gwt.user.client.ui.UIObject;
-import com.google.gwt.user.client.ui.Widget;
-import com.google.gwtexpui.globalkey.client.GlobalKey;
-import com.google.gwtexpui.globalkey.client.KeyCommand;
-import com.google.gwtexpui.globalkey.client.KeyCommandSet;
-import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
-import com.google.gwtorm.client.KeyUtil;
-
-import org.eclipse.jgit.diff.Edit;
-
-import java.sql.Timestamp;
-import java.util.ArrayList;
-import java.util.List;
-
-abstract class AbstractPatchContentTable extends NavigationTable<Object>
-    implements CommentEditorContainer, FocusHandler, BlurHandler {
-  public static final int R_HEAD = 0;
-  static final short FILE_SIDE_A = (short) 0;
-  static final short FILE_SIDE_B = (short) 1;
-  protected PatchTable fileList;
-  protected AccountInfoCache accountCache = AccountInfoCache.empty();
-  protected Patch.Key patchKey;
-  protected PatchSet.Id idSideA;
-  protected PatchSet.Id idSideB;
-  protected boolean onlyOneHunk;
-  protected PatchSetSelectBox headerSideA;
-  protected PatchSetSelectBox headerSideB;
-  protected Image iconA;
-  protected Image iconB;
-
-  private final KeyCommandSet keysComment;
-  private HandlerRegistration regComment;
-  private final KeyCommandSet keysOpenByEnter;
-  private HandlerRegistration regOpenByEnter;
-  private CommentLinkProcessor commentLinkProcessor;
-  boolean isDisplayBinary;
-
-  protected AbstractPatchContentTable() {
-    keysNavigation.add(new PrevKeyCommand(0, 'k', PatchUtil.C.linePrev()));
-    keysNavigation.add(new NextKeyCommand(0, 'j', PatchUtil.C.lineNext()));
-    keysNavigation.add(new PrevChunkKeyCmd(0, 'p', PatchUtil.C.chunkPrev()));
-    keysNavigation.add(new NextChunkKeyCmd(0, 'n', PatchUtil.C.chunkNext()));
-    keysNavigation.add(new PrevCommentCmd(0, 'P', PatchUtil.C.commentPrev()));
-    keysNavigation.add(new NextCommentCmd(0, 'N', PatchUtil.C.commentNext()));
-
-    keysAction.add(new OpenKeyCommand(0, 'o', PatchUtil.C.expandComment()));
-    keysOpenByEnter = new KeyCommandSet(Gerrit.C.sectionNavigation());
-    keysOpenByEnter.add(new OpenKeyCommand(0, KeyCodes.KEY_ENTER, PatchUtil.C.expandComment()));
-
-    if (Gerrit.isSignedIn()) {
-      keysAction.add(new InsertCommentCommand(0, 'c', PatchUtil.C
-          .commentInsert()));
-
-      // See CommentEditorPanel
-      //
-      keysComment = new KeyCommandSet(PatchUtil.C.commentEditorSet());
-      keysComment.add(new NoOpKeyCommand(KeyCommand.M_CTRL, 's', PatchUtil.C
-          .commentSaveDraft()));
-      keysComment.add(new NoOpKeyCommand(0, KeyCodes.KEY_ESCAPE, PatchUtil.C
-          .commentCancelEdit()));
-    } else {
-      keysComment = null;
-    }
-
-    table.setStyleName(Gerrit.RESOURCES.css().patchContentTable());
-  }
-
-  abstract void createFileCommentEditorOnSideA();
-
-  abstract void createFileCommentEditorOnSideB();
-
-  protected void initHeaders(PatchScript script, PatchSetDetail detail) {
-    headerSideA = new PatchSetSelectBox(PatchSetSelectBox.Side.A);
-    headerSideA.display(detail, script, patchKey, idSideA, idSideB);
-    headerSideA.addDoubleClickHandler(new DoubleClickHandler() {
-      @Override
-      public void onDoubleClick(DoubleClickEvent event) {
-        if (headerSideA.isFileOrCommitMessage()) {
-          createFileCommentEditorOnSideA();
-        }
-      }
-    });
-    headerSideB = new PatchSetSelectBox(PatchSetSelectBox.Side.B);
-    headerSideB.display(detail, script, patchKey, idSideA, idSideB);
-    headerSideB.addDoubleClickHandler(new DoubleClickHandler() {
-      @Override
-      public void onDoubleClick(DoubleClickEvent event) {
-        if (headerSideB.isFileOrCommitMessage()) {
-          createFileCommentEditorOnSideB();
-        }
-      }
-    });
-
-    // Prepare icons.
-    iconA = new Image(Gerrit.RESOURCES.addFileComment());
-    iconA.setTitle(PatchUtil.C.addFileCommentToolTip());
-    iconA.addStyleName(Gerrit.RESOURCES.css().link());
-    iconA.addClickHandler(new ClickHandler() {
-      @Override
-      public void onClick(ClickEvent event) {
-        createFileCommentEditorOnSideA();
-      }
-    });
-    iconB = new Image(Gerrit.RESOURCES.addFileComment());
-    iconB.setTitle(PatchUtil.C.addFileCommentToolTip());
-    iconB.addStyleName(Gerrit.RESOURCES.css().link());
-    iconB.addClickHandler(new ClickHandler() {
-      @Override
-      public void onClick(ClickEvent event) {
-        createFileCommentEditorOnSideB();
-      }
-    });
-  }
-
-  @Override
-  public void notifyDraftDelta(final int delta) {
-    if (fileList != null) {
-      fileList.notifyDraftDelta(patchKey, delta);
-    }
-
-    Widget p = getParent();
-    while (p != null) {
-      if (p instanceof CommentEditorContainer) {
-        ((CommentEditorContainer) p).notifyDraftDelta(delta);
-        break;
-      }
-      p = p.getParent();
-    }
-  }
-
-  @Override
-  public void remove(CommentEditorPanel panel) {
-    final int nRows = table.getRowCount();
-    for (int row = 0; row < nRows; row++) {
-      final int nCells = table.getCellCount(row);
-      for (int cell = 0; cell < nCells; cell++) {
-        if (table.getWidget(row, cell) == panel) {
-          destroyEditor(row, cell);
-          Widget p = table;
-          while (p != null) {
-            if (p instanceof Focusable) {
-              ((Focusable) p).setFocus(true);
-              break;
-            }
-            p = p.getParent();
-          }
-
-          if (table.getCellFormatter().getStyleName(row - 1, cell)
-              .contains(Gerrit.RESOURCES.css().commentHolder())) {
-            table.getCellFormatter().addStyleName(row - 1, cell,
-                Gerrit.RESOURCES.css().commentPanelLast());
-          }
-          return;
-        }
-      }
-    }
-  }
-
-  @Override
-  public void setRegisterKeys(final boolean on) {
-    super.setRegisterKeys(on);
-    if (on && keysComment != null && regComment == null) {
-      regComment = GlobalKey.add(this, keysComment);
-    } else if (!on && regComment != null) {
-      regComment.removeHandler();
-      regComment = null;
-    }
-
-    if (on && keysOpenByEnter != null && regOpenByEnter == null) {
-      regOpenByEnter = GlobalKey.add(this, keysOpenByEnter);
-    } else if (!on && regOpenByEnter != null) {
-      regOpenByEnter.removeHandler();
-      regOpenByEnter = null;
-    }
-  }
-
-  public void display(final Patch.Key k, final PatchSet.Id a,
-      final PatchSet.Id b, final PatchScript s, final PatchSetDetail d) {
-    patchKey = k;
-    idSideA = a;
-    idSideB = b;
-
-    render(s, d);
-  }
-
-  void setCommentLinkProcessor(CommentLinkProcessor commentLinkProcessor) {
-    this.commentLinkProcessor = commentLinkProcessor;
-  }
-
-  protected boolean hasDifferences(PatchScript script) {
-    return hasEdits(script) || hasMeta(script) || hasComments(script);
-  }
-
-  public boolean isPureMetaChange(PatchScript script) {
-    return !hasEdits(script) && hasMeta(script);
-  }
-
-  // True if there are differences between the two patch sets
-  private boolean hasEdits(PatchScript script) {
-    for (Edit e : script.getEdits()) {
-      if (e.getType() != Edit.Type.EMPTY) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  // True if one of the two patch sets has comments
-  private boolean hasComments(PatchScript script) {
-    return !script.getCommentDetail().getCommentsA().isEmpty()
-        || !script.getCommentDetail().getCommentsB().isEmpty();
-  }
-
-  // True if this change is a mode change or a pure rename/copy
-  private boolean hasMeta(PatchScript script) {
-    return !script.getPatchHeader().isEmpty();
-  }
-
-  protected void appendNoDifferences(SafeHtmlBuilder m) {
-    m.openTr();
-    m.openTd();
-    m.setAttribute("colspan", 5);
-    m.openDiv();
-    m.addStyleName(Gerrit.RESOURCES.css().patchNoDifference());
-    m.append(PatchUtil.C.noDifference());
-    m.closeDiv();
-    m.closeTd();
-    m.closeTr();
-  }
-
-  protected SparseHtmlFile getSparseHtmlFileA(PatchScript s) {
-    DiffPreferencesInfo dp = s.getDiffPrefs();
-    dp.showWhitespaceErrors = false;
-
-    PrettyFormatter f = ClientSideFormatter.FACTORY.get();
-    f.setDiffPrefs(dp);
-    f.setFileName(s.getA().getPath());
-    f.setEditFilter(PrettyFormatter.A);
-    f.setEditList(s.getEdits());
-    f.format(s.getA());
-    return f;
-  }
-
-  protected SparseHtmlFile getSparseHtmlFileB(PatchScript s) {
-    DiffPreferencesInfo dp = s.getDiffPrefs();
-
-    SparseFileContent b = s.getB();
-    PrettyFormatter f = ClientSideFormatter.FACTORY.get();
-    f.setDiffPrefs(dp);
-    f.setFileName(b.getPath());
-    f.setEditFilter(PrettyFormatter.B);
-    f.setEditList(s.getEdits());
-
-    if (s.getA().isWholeFile() && !b.isWholeFile()) {
-      b = b.apply(s.getA(), s.getEdits());
-    }
-    f.format(b);
-    return f;
-  }
-
-  protected String getUrlA() {
-    final String rawBase = GWT.getHostPageBaseURL() + "cat/";
-    final String url;
-    if (idSideA == null) {
-      url = rawBase + KeyUtil.encode(patchKey.toString()) + "^1";
-    } else {
-      Patch.Key k = new Patch.Key(idSideA, patchKey.get());
-      url = rawBase + KeyUtil.encode(k.toString()) + "^0";
-    }
-    return url;
-  }
-
-  protected String getUrlB() {
-    final String rawBase = GWT.getHostPageBaseURL() + "cat/";
-    return rawBase + KeyUtil.encode(patchKey.toString()) + "^0";
-  }
-
-  protected abstract void render(PatchScript script, final PatchSetDetail detail);
-
-  protected abstract void onInsertComment(PatchLine pl);
-
-  public abstract void display(CommentDetail comments, boolean expandComments);
-
-  @Override
-  protected Object getRowItemKey(final Object item) {
-    return null;
-  }
-
-  protected void initScript(final PatchScript script) {
-    if (script.getEdits().size() == 1) {
-      final SparseFileContent a = script.getA();
-      final SparseFileContent b = script.getB();
-      onlyOneHunk = a.size() == 0 || b.size() == 0;
-    } else {
-      onlyOneHunk = false;
-    }
-  }
-
-  private boolean isChunk(final int row) {
-    final Object o = getRowItem(row);
-    if (!onlyOneHunk && o instanceof PatchLine) {
-      final PatchLine pl = (PatchLine) o;
-      switch (pl.getType()) {
-        case DELETE:
-        case INSERT:
-        case REPLACE:
-          return true;
-        case CONTEXT:
-          break;
-      }
-    } else if (o instanceof CommentList) {
-      return true;
-    }
-    return false;
-  }
-
-  private int findChunkStart(int row) {
-    while (0 <= row && isChunk(row)) {
-      row--;
-    }
-    return row + 1;
-  }
-
-  private int findChunkEnd(int row) {
-    final int max = table.getRowCount();
-    while (row < max && isChunk(row)) {
-      row++;
-    }
-    return row - 1;
-  }
-
-  private static int oneBefore(final int begin) {
-    return 1 <= begin ? begin - 1 : begin;
-  }
-
-  private int oneAfter(final int end) {
-    return end + 1 < table.getRowCount() ? end + 1 : end;
-  }
-
-  private void moveToPrevChunk(int row) {
-    while (0 <= row && isChunk(row)) {
-      row--;
-    }
-    for (; 0 <= row; row--) {
-      if (isChunk(row)) {
-        final int start = findChunkStart(row);
-        movePointerTo(start, false);
-        scrollIntoView(oneBefore(start), oneAfter(row));
-        return;
-      }
-    }
-
-    // No prior hunk found? Try to hit the first line in the file.
-    //
-    for (row = 0; row < table.getRowCount(); row++) {
-      if (getRowItem(row) != null) {
-        movePointerTo(row);
-        break;
-      }
-    }
-  }
-
-  private void moveToNextChunk(int row) {
-    final int max = table.getRowCount();
-    while (row < max && isChunk(row)) {
-      row++;
-    }
-    for (; row < max; row++) {
-      if (isChunk(row)) {
-        movePointerTo(row, false);
-        scrollIntoView(oneBefore(row), oneAfter(findChunkEnd(row)));
-        return;
-      }
-    }
-
-    // No next hunk found? Try to hit the last line in the file.
-    //
-    for (row = max - 1; row >= 0; row--) {
-      if (getRowItem(row) != null) {
-        movePointerTo(row);
-        break;
-      }
-    }
-  }
-
-  private void moveToPrevComment(int row) {
-    while (0 <= row && isComment(row)) {
-      row--;
-    }
-    for (; 0 <= row; row--) {
-      if (isComment(row)) {
-        movePointerTo(row, false);
-        scrollIntoView(oneBefore(row), oneAfter(row));
-        return;
-      }
-    }
-
-    // No prior comment found? Try to hit the first line in the file.
-    //
-    for (row = 0; row < table.getRowCount(); row++) {
-      if (getRowItem(row) != null) {
-        movePointerTo(row);
-        break;
-      }
-    }
-  }
-
-  private void moveToNextComment(int row) {
-    final int max = table.getRowCount();
-    while (row < max && isComment(row)) {
-      row++;
-    }
-    for (; row < max; row++) {
-      if (isComment(row)) {
-        movePointerTo(row, false);
-        scrollIntoView(oneBefore(row), oneAfter(row));
-        return;
-      }
-    }
-
-    // No next comment found? Try to hit the last line in the file.
-    //
-    for (row = max - 1; row >= 0; row--) {
-      if (getRowItem(row) != null) {
-        movePointerTo(row);
-        break;
-      }
-    }
-  }
-
-  private boolean isComment(int row) {
-    return getRowItem(row) instanceof CommentList;
-  }
-
-  /**
-   * Invokes createCommentEditor() with an empty string as value for the comment
-   * parent UUID. This method is invoked by callers that want to create an
-   * editor for a comment that is not a reply.
-   */
-  protected void createCommentEditor(final int suggestRow, final int column,
-      final int line, final short file) {
-    if (Gerrit.isSignedIn()) {
-      if (R_HEAD <= line) {
-        final Patch.Key parentKey;
-        final short side;
-        switch (file) {
-          case 0:
-            if (idSideA == null) {
-              parentKey = new Patch.Key(idSideB, patchKey.get());
-              side = (short) 0;
-            } else {
-              parentKey = new Patch.Key(idSideA, patchKey.get());
-              side = (short) 1;
-            }
-            break;
-          case 1:
-            parentKey = new Patch.Key(idSideB, patchKey.get());
-            side = (short) 1;
-            break;
-          default:
-            throw new RuntimeException("unexpected file id " + file);
-        }
-
-        final PatchLineComment newComment = new PatchLineComment(
-            new PatchLineComment.Key(parentKey, null), line,
-            Gerrit.getUserAccount().getId(), null,
-            new Timestamp(System.currentTimeMillis()));
-        newComment.setSide(side);
-        newComment.setMessage("");
-
-        findOrCreateCommentEditor(suggestRow, column, newComment, true)
-            .setFocus(true);
-      }
-    } else {
-      Gerrit.doSignIn(History.getToken());
-    }
-  }
-
-  /**
-   * Update cursor after selecting a comment.
-   *
-   * @param newComment comment that was selected.
-   */
-  protected void updateCursor(final PatchLineComment newComment) {
-  }
-
-  abstract void insertFileCommentRow(final int row);
-
-  private CommentEditorPanel findOrCreateCommentEditor(final int suggestRow,
-      final int column, final PatchLineComment newComment, final boolean create) {
-    int row = suggestRow;
-    int[] spans = new int[column + 1];
-    FIND_ROW: while (row < table.getRowCount()) {
-      int col = 0;
-      for (int cell = 0; row < table.getRowCount()
-          && cell < table.getCellCount(row); cell++) {
-        while (col < column && 0 < spans[col]) {
-          spans[col++]--;
-        }
-        spans[col] = table.getFlexCellFormatter().getRowSpan(row, cell);
-        if (col == column) {
-          final Widget w = table.getWidget(row, cell);
-          if (w instanceof CommentEditorPanel
-              && ((CommentEditorPanel) w).getComment().getKey().getParentKey()
-                  .equals(newComment.getKey().getParentKey())) {
-            // Don't insert two editors on the same position, it doesn't make
-            // any sense to the user.
-            //
-            return ((CommentEditorPanel) w);
-
-          } else if (w instanceof CommentPanel) {
-            if (newComment != null && newComment.getParentUuid() != null) {
-              // If we are a reply, we were given the exact row to insert
-              // ourselves at. We should be before this panel so break.
-              //
-              break FIND_ROW;
-            }
-            row++;
-            cell--;
-          } else {
-            break FIND_ROW;
-          }
-        }
-      }
-    }
-
-    if (newComment == null || !create) {
-      return null;
-    }
-
-    final CommentEditorPanel ed =
-        new CommentEditorPanel(newComment, commentLinkProcessor);
-    ed.addFocusHandler(this);
-    ed.addBlurHandler(this);
-    boolean isCommentRow = false;
-    boolean needInsert = false;
-    if (row < table.getRowCount()) {
-      for (int cell = 0; cell < table.getCellCount(row); cell++) {
-        final Widget w = table.getWidget(row, cell);
-        if (w instanceof CommentEditorPanel || w instanceof CommentPanel) {
-          if (column == cell) {
-            needInsert = true;
-          }
-          isCommentRow = true;
-        }
-      }
-    }
-    if (needInsert || !isCommentRow) {
-      if (newComment.getLine() == R_HEAD) {
-        insertFileCommentRow(row);
-      } else {
-        insertRow(row);
-      }
-      styleCommentRow(row);
-    }
-    table.setWidget(row, column, ed);
-    styleLastCommentCell(row, column);
-
-    int span = 1;
-    for (int r = row + 1; r < table.getRowCount(); r++) {
-      boolean hasComment = false;
-      for (int c = 0; c < table.getCellCount(r); c++) {
-        final Widget w = table.getWidget(r, c);
-        if (w instanceof CommentPanel || w instanceof CommentEditorPanel) {
-          if (c != column) {
-            hasComment = true;
-            break;
-          }
-        }
-      }
-      if (hasComment) {
-        table.removeCell(r, column);
-        span++;
-      } else {
-        break;
-      }
-    }
-    if (span > 1) {
-      table.getFlexCellFormatter().setRowSpan(row, column, span);
-    }
-
-    for (int r = row - 1; r > 0; r--) {
-      if (getRowItem(r) instanceof CommentList) {
-        continue;
-      } else if (getRowItem(r) != null) {
-        movePointerTo(r);
-        break;
-      }
-    }
-
-    updateCursor(newComment);
-    return ed;
-  }
-
-  protected void insertRow(final int row) {
-    table.insertRow(row);
-    table.getCellFormatter().setStyleName(row, 0,
-        Gerrit.RESOURCES.css().iconCell());
-  }
-
-  @Override
-  protected void onOpenRow(final int row) {
-    final Object item = getRowItem(row);
-    if (item instanceof CommentList) {
-      for (final CommentPanel p : ((CommentList) item).panels) {
-        p.setOpen(!p.isOpen());
-      }
-    }
-  }
-
-  public void setAccountInfoCache(final AccountInfoCache aic) {
-    assert aic != null;
-    accountCache = aic;
-  }
-
-  private void destroyEditor(final int row, final int col) {
-    table.clearCell(row, col);
-    final int span = table.getFlexCellFormatter().getRowSpan(row, col);
-    boolean removeRow = true;
-    final int nCells = table.getCellCount(row);
-    for (int cell = 0; cell < nCells; cell++) {
-      if (table.getWidget(row, cell) != null) {
-        removeRow = false;
-        break;
-      }
-    }
-    if (removeRow) {
-      destroyCommentRow(row);
-    } else {
-      destroyComment(row, col, span);
-    }
-  }
-
-  protected void destroyCommentRow(int row) {
-    for (int r = row - 1; 0 <= r; r--) {
-      boolean data = false;
-      for (int c = 0; c < table.getCellCount(r); c++) {
-        data |= table.getWidget(r, c) != null;
-        final int s = table.getFlexCellFormatter().getRowSpan(r, c) - 1;
-        if (r + s == row) {
-          table.getFlexCellFormatter().setRowSpan(r, c, s);
-        }
-      }
-      if (!data) {
-        break;
-      }
-    }
-    table.removeRow(row);
-  }
-
-  private void destroyComment(int row, int col, int span) {
-    table.getFlexCellFormatter().setStyleName(//
-        row, col, Gerrit.RESOURCES.css().diffText());
-
-    if (span != 1) {
-      table.getFlexCellFormatter().setRowSpan(row, col, 1);
-      for (int r = row + 1; r < row + span; r++) {
-        table.insertCell(r, col);
-
-        table.getFlexCellFormatter().setStyleName(//
-            r, col, Gerrit.RESOURCES.css().diffText());
-      }
-    }
-  }
-
-  protected void bindComment(final int row, final int col,
-      final PatchLineComment line, boolean expandComment) {
-    if (line.getStatus() == PatchLineComment.Status.DRAFT) {
-      final CommentEditorPanel plc =
-          new CommentEditorPanel(line, commentLinkProcessor);
-      plc.addFocusHandler(this);
-      plc.addBlurHandler(this);
-      table.setWidget(row, col, plc);
-      styleLastCommentCell(row, col);
-
-    } else {
-      final AccountInfo author = FormatUtil.asInfo(accountCache.get(line.getAuthor()));
-      final PublishedCommentPanel panel =
-          new PublishedCommentPanel(author, line);
-      panel.setOpen(expandComment);
-      panel.addFocusHandler(this);
-      panel.addBlurHandler(this);
-      table.setWidget(row, col, panel);
-      styleLastCommentCell(row, col);
-
-      CommentList l = (CommentList) getRowItem(row);
-      if (l == null) {
-        l = new CommentList();
-        setRowItem(row, l);
-      }
-      l.comments.add(line);
-      l.panels.add(panel);
-    }
-
-    styleCommentRow(row);
-  }
-
-  @Override
-  public void onFocus(FocusEvent event) {
-    // when the comment panel gets focused (actually when a button inside the
-    // comment panel gets focused) we have to unregister the key binding for
-    // ENTER that expands/collapses the comment panel, if we don't do this the
-    // focused button in the comment panel cannot be triggered by pressing ENTER
-    // since ENTER would then be already consumed by this key binding
-    if (regOpenByEnter != null) {
-      regOpenByEnter.removeHandler();
-      regOpenByEnter = null;
-    }
-  }
-
-  @Override
-  public void onBlur(BlurEvent event) {
-    // when the comment panel gets blurred (actually when a button inside the
-    // comment panel gets blurred) we have to re-register the key binding for
-    // ENTER that expands/collapses the comment panel
-    if (keysOpenByEnter != null && regOpenByEnter == null) {
-      regOpenByEnter = GlobalKey.add(this, keysOpenByEnter);
-    }
-  }
-
-  private void styleCommentRow(final int row) {
-    final CellFormatter fmt = table.getCellFormatter();
-    final Element iconCell = fmt.getElement(row, 0);
-    UIObject.setStyleName(DOM.getParent(iconCell), Gerrit.RESOURCES.css()
-        .commentHolder(), true);
-  }
-
-  private void styleLastCommentCell(final int row, final int col) {
-    final CellFormatter fmt = table.getCellFormatter();
-    fmt.removeStyleName(row - 1, col, //
-        Gerrit.RESOURCES.css().commentPanelLast());
-    fmt.setStyleName(row, col, Gerrit.RESOURCES.css().commentHolder());
-    fmt.addStyleName(row, col, Gerrit.RESOURCES.css().commentPanelLast());
-    if (!fmt.getStyleName(row, col - 1).contains(Gerrit.RESOURCES.css().commentHolder())) {
-      fmt.addStyleName(row, col, Gerrit.RESOURCES.css().commentHolderLeftmost());
-    }
-  }
-
-  protected static class CommentList {
-    final List<PatchLineComment> comments = new ArrayList<>();
-    final List<PublishedCommentPanel> panels = new ArrayList<>();
-  }
-
-  public static class NoOpKeyCommand extends NeedsSignInKeyCommand {
-    public NoOpKeyCommand(int mask, int key, String help) {
-      super(mask, key, help);
-    }
-
-    @Override
-    public void onKeyPress(final KeyPressEvent event) {
-    }
-  }
-
-  public class InsertCommentCommand extends NeedsSignInKeyCommand {
-    public InsertCommentCommand(int mask, int key, String help) {
-      super(mask, key, help);
-    }
-
-    @Override
-    public void onKeyPress(final KeyPressEvent event) {
-      ensurePointerVisible();
-      for (int row = getCurrentRow(); 0 <= row; row--) {
-        final Object item = getRowItem(row);
-        if (item instanceof PatchLine) {
-          onInsertComment((PatchLine) item);
-          return;
-        } else if (item instanceof CommentList) {
-          continue;
-        } else {
-          return;
-        }
-      }
-    }
-  }
-
-  public class PrevChunkKeyCmd extends KeyCommand {
-    public PrevChunkKeyCmd(int mask, int key, String help) {
-      super(mask, key, help);
-    }
-
-    @Override
-    public void onKeyPress(final KeyPressEvent event) {
-      ensurePointerVisible();
-      moveToPrevChunk(getCurrentRow());
-    }
-  }
-
-  public class NextChunkKeyCmd extends KeyCommand {
-    public NextChunkKeyCmd(int mask, int key, String help) {
-      super(mask, key, help);
-    }
-
-    @Override
-    public void onKeyPress(final KeyPressEvent event) {
-      ensurePointerVisible();
-      moveToNextChunk(getCurrentRow());
-    }
-  }
-
-  public class PrevCommentCmd extends KeyCommand {
-    public PrevCommentCmd(int mask, int key, String help) {
-      super(mask, key, help);
-    }
-
-    @Override
-    public void onKeyPress(final KeyPressEvent event) {
-      ensurePointerVisible();
-      moveToPrevComment(getCurrentRow());
-    }
-  }
-
-  public class NextCommentCmd extends KeyCommand {
-    public NextCommentCmd(int mask, int key, String help) {
-      super(mask, key, help);
-    }
-
-    @Override
-    public void onKeyPress(final KeyPressEvent event) {
-      ensurePointerVisible();
-      moveToNextComment(getCurrentRow());
-    }
-  }
-
-  private class PublishedCommentPanel extends CommentPanel implements
-      ClickHandler {
-    final PatchLineComment comment;
-    final Button reply;
-    final Button replyDone;
-
-    PublishedCommentPanel(final AccountInfo author, final PatchLineComment c) {
-      super(author, c.getWrittenOn(), c.getMessage(), commentLinkProcessor);
-      this.comment = c;
-
-      reply = new Button(PatchUtil.C.buttonReply());
-      reply.addClickHandler(this);
-      addButton(reply);
-
-      replyDone = new Button(PatchUtil.C.buttonReplyDone());
-      replyDone.addClickHandler(this);
-      addButton(replyDone);
-    }
-
-    @Override
-    public void onClick(final ClickEvent event) {
-      if (Gerrit.isSignedIn()) {
-        if (reply == event.getSource()) {
-          createReplyEditor();
-        } else if (replyDone == event.getSource()) {
-          cannedReply(PatchUtil.C.cannedReplyDone());
-        }
-
-      } else {
-        Gerrit.doSignIn(History.getToken());
-      }
-    }
-
-    private void createReplyEditor() {
-      final PatchLineComment newComment = newComment();
-      newComment.setMessage("");
-      findOrCreateEditor(newComment, true).setFocus(true);
-    }
-
-    private void cannedReply(String message) {
-      final PatchLineComment newComment = newComment();
-      newComment.setMessage(message);
-      CommentEditorPanel p = findOrCreateEditor(newComment, false);
-      if (p == null) {
-        enableButtons(false);
-        final PatchSet.Id psId = newComment.getKey().getParentKey().getParentKey();
-        CommentInfo in = CommentEditorPanel.toInput(newComment);
-        CommentApi.createDraft(psId, in,
-            new GerritCallback<CommentInfo>() {
-              @Override
-              public void onSuccess(CommentInfo result) {
-                enableButtons(true);
-                notifyDraftDelta(1);
-                findOrCreateEditor(CommentEditorPanel.toComment(
-                    psId, newComment.getKey().getParentKey().get(), result),
-                  true).setOpen(false);
-              }
-
-              @Override
-              public void onFailure(Throwable caught) {
-                enableButtons(true);
-                super.onFailure(caught);
-              }
-            });
-      } else {
-        if (!p.isOpen()) {
-          p.setOpen(true);
-        }
-        p.setFocus(true);
-      }
-    }
-
-    private CommentEditorPanel findOrCreateEditor(
-        PatchLineComment newComment, boolean create) {
-      int row = rowOf(getElement());
-      int column = columnOf(getElement());
-      return findOrCreateCommentEditor(row + 1, column, newComment, create);
-    }
-
-    private PatchLineComment newComment() {
-      PatchLineComment newComment =
-          new PatchLineComment(new PatchLineComment.Key(comment.getKey()
-              .getParentKey(), null), comment.getLine(), Gerrit
-              .getUserAccount().getId(), comment.getKey().get(),
-              new Timestamp(System.currentTimeMillis()));
-      newComment.setSide(comment.getSide());
-      return newComment;
-    }
-  }
-}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/CommentEditorContainer.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/CommentEditorContainer.java
deleted file mode 100644
index b1381ca..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/CommentEditorContainer.java
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (C) 2010 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.client.patches;
-
-public interface CommentEditorContainer {
-  void notifyDraftDelta(int delta);
-
-  void remove(CommentEditorPanel panel);
-}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/CommentEditorPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/CommentEditorPanel.java
deleted file mode 100644
index 3cf29e5..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/CommentEditorPanel.java
+++ /dev/null
@@ -1,371 +0,0 @@
-// Copyright (C) 2008 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.client.patches;
-
-import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.client.change.LocalComments;
-import com.google.gerrit.client.changes.CommentApi;
-import com.google.gerrit.client.changes.CommentInfo;
-import com.google.gerrit.client.rpc.GerritCallback;
-import com.google.gerrit.client.ui.CommentLinkProcessor;
-import com.google.gerrit.client.ui.CommentPanel;
-import com.google.gerrit.extensions.client.Side;
-import com.google.gerrit.reviewdb.client.Patch;
-import com.google.gerrit.reviewdb.client.PatchLineComment;
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gwt.core.client.JavaScriptObject;
-import com.google.gwt.event.dom.client.ClickEvent;
-import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.event.dom.client.DoubleClickEvent;
-import com.google.gwt.event.dom.client.DoubleClickHandler;
-import com.google.gwt.event.dom.client.KeyDownEvent;
-import com.google.gwt.event.dom.client.KeyDownHandler;
-import com.google.gwt.user.client.Timer;
-import com.google.gwt.user.client.ui.Button;
-import com.google.gwt.user.client.ui.Widget;
-import com.google.gwtexpui.globalkey.client.NpTextArea;
-import com.google.gwtjsonrpc.common.AsyncCallback;
-import com.google.gwtjsonrpc.common.VoidResult;
-
-import java.sql.Timestamp;
-
-public class CommentEditorPanel extends CommentPanel implements ClickHandler,
-    DoubleClickHandler {
-  private static final int INITIAL_COLS = 60;
-  private static final int INITIAL_LINES = 5;
-  private static final int MAX_LINES = 30;
-  private static final AsyncCallback<VoidResult> NULL_CALLBACK =
-      new AsyncCallback<VoidResult>() {
-        @Override
-        public void onFailure(Throwable caught) {
-        }
-
-        @Override
-        public void onSuccess(VoidResult result) {
-        }
-      };
-
-  private PatchLineComment comment;
-
-  private final NpTextArea text;
-  private final Button edit;
-  private final Button save;
-  private final Button cancel;
-  private final Button discard;
-  private final Timer expandTimer;
-
-  public CommentEditorPanel(final PatchLineComment plc,
-      final CommentLinkProcessor commentLinkProcessor) {
-    super(commentLinkProcessor);
-    comment = plc;
-
-    addStyleName(Gerrit.RESOURCES.css().commentEditorPanel());
-    setAuthorNameText(Gerrit.getUserAccount(), PatchUtil.C.draft());
-    setMessageText(plc.getMessage());
-    addDoubleClickHandler(this);
-
-    expandTimer = new Timer() {
-      @Override
-      public void run() {
-        expandText();
-      }
-    };
-    text = new NpTextArea();
-    text.setText(comment.getMessage());
-    text.setCharacterWidth(INITIAL_COLS);
-    text.setVisibleLines(INITIAL_LINES);
-    text.setSpellCheck(true);
-    text.addKeyDownHandler(new KeyDownHandler() {
-      @Override
-      public void onKeyDown(final KeyDownEvent event) {
-        if ((event.isControlKeyDown() || event.isMetaKeyDown())
-            && !event.isAltKeyDown() && !event.isShiftKeyDown()) {
-          switch (event.getNativeKeyCode()) {
-            case 's':
-            case 'S':
-              event.preventDefault();
-              onSave(NULL_CALLBACK);
-              return;
-          }
-        }
-
-        expandTimer.schedule(250);
-      }
-    });
-    addContent(text);
-
-    edit = new Button();
-    edit.setText(PatchUtil.C.buttonEdit());
-    edit.addClickHandler(this);
-    addButton(edit);
-
-    save = new Button();
-    save.setText(PatchUtil.C.buttonSave());
-    save.addClickHandler(this);
-    addButton(save);
-
-    cancel = new Button();
-    cancel.setText(PatchUtil.C.buttonCancel());
-    cancel.addClickHandler(this);
-    addButton(cancel);
-
-    discard = new Button();
-    discard.setText(PatchUtil.C.buttonDiscard());
-    discard.addClickHandler(this);
-    addButton(discard);
-
-    setOpen(true);
-    if (isNew()) {
-      edit();
-    } else {
-      render();
-    }
-  }
-
-  private void expandText() {
-    final double cols = text.getCharacterWidth();
-    int rows = 2;
-    for (final String line : text.getText().split("\n")) {
-      rows += Math.ceil((1.0 + line.length()) / cols);
-    }
-    rows = Math.max(INITIAL_LINES, Math.min(rows, MAX_LINES));
-    if (text.getVisibleLines() != rows) {
-      text.setVisibleLines(rows);
-    }
-  }
-
-  private void edit() {
-    if (!isOpen()) {
-      setOpen(true);
-    }
-    text.setText(comment.getMessage());
-    expandText();
-    stateEdit(true);
-    text.setFocus(true);
-  }
-
-  private void render() {
-    final Timestamp on = comment.getWrittenOn();
-    setDateText(PatchUtil.M.draftSaved(new java.util.Date(on.getTime())));
-    setMessageText(comment.getMessage());
-    stateEdit(false);
-  }
-
-  private void stateEdit(final boolean inEdit) {
-    expandTimer.cancel();
-    setMessageTextVisible(!inEdit);
-    edit.setVisible(!inEdit);
-
-    if (inEdit) {
-      text.setVisible(true);
-    } else {
-      text.setFocus(false);
-      text.setVisible(false);
-    }
-
-    save.setVisible(inEdit);
-    cancel.setVisible(inEdit && !isNew());
-    discard.setVisible(inEdit);
-  }
-
-  void setFocus(final boolean take) {
-    if (take && !isOpen()) {
-      setOpen(true);
-    }
-    if (text.isVisible()) {
-      text.setFocus(take);
-    } else if (take) {
-      edit();
-    }
-  }
-
-  boolean isNew() {
-    return comment.getKey().get() == null;
-  }
-
-  public PatchLineComment getComment() {
-    return comment;
-  }
-
-  @Override
-  public void onDoubleClick(final DoubleClickEvent event) {
-    edit();
-  }
-
-  @Override
-  public void onClick(final ClickEvent event) {
-    final Widget sender = (Widget) event.getSource();
-    if (sender == edit) {
-      edit();
-
-    } else if (sender == save) {
-      onSave(NULL_CALLBACK);
-
-    } else if (sender == cancel) {
-      render();
-
-    } else if (sender == discard) {
-      onDiscard();
-    }
-  }
-
-  public void saveDraft(AsyncCallback<VoidResult> onSave) {
-    if (isOpen() && text.isVisible()) {
-      onSave(onSave);
-    } else {
-      onSave.onSuccess(VoidResult.INSTANCE);
-    }
-  }
-
-  private void onSave(final AsyncCallback<VoidResult> onSave) {
-    expandTimer.cancel();
-    final String txt = text.getText().trim();
-    if ("".equals(txt)) {
-      return;
-    }
-
-    comment.setMessage(txt);
-    text.setFocus(false);
-    text.setReadOnly(true);
-    save.setEnabled(false);
-    cancel.setEnabled(false);
-    discard.setEnabled(false);
-
-    final PatchSet.Id psId = comment.getKey().getParentKey().getParentKey();
-    final LocalComments lc = new LocalComments(psId);
-    final boolean wasNew = isNew();
-    GerritCallback<CommentInfo> cb = new GerritCallback<CommentInfo>() {
-      @Override
-      public void onSuccess(CommentInfo result) {
-        notifyDraftDelta(wasNew ? 1 : 0);
-        comment = toComment(psId, comment.getKey().getParentKey().get(), result);
-        text.setReadOnly(false);
-        save.setEnabled(true);
-        cancel.setEnabled(true);
-        discard.setEnabled(true);
-        render();
-        onSave.onSuccess(VoidResult.INSTANCE);
-      }
-
-      @Override
-      public void onFailure(final Throwable caught) {
-        text.setReadOnly(false);
-        text.setFocus(true);
-        save.setEnabled(true);
-        cancel.setEnabled(true);
-        discard.setEnabled(true);
-        lc.setInlineComment(toInput(comment));
-        super.onFailure(caught);
-        onSave.onFailure(caught);
-      }
-    };
-    CommentInfo input = toInput(comment);
-    if (wasNew) {
-      CommentApi.createDraft(psId, input, cb);
-    } else {
-      CommentApi.updateDraft(psId, input.id(), input, cb);
-    }
-  }
-
-  private void notifyDraftDelta(final int delta) {
-    CommentEditorContainer c = getContainer();
-    if (c != null) {
-      c.notifyDraftDelta(delta);
-    }
-  }
-
-  private void onDiscard() {
-    expandTimer.cancel();
-    if (isNew()) {
-      text.setFocus(false);
-      removeUI();
-      return;
-    }
-
-    text.setFocus(false);
-    text.setReadOnly(true);
-    save.setEnabled(false);
-    cancel.setEnabled(false);
-    discard.setEnabled(false);
-
-    CommentApi.deleteDraft(
-        comment.getKey().getParentKey().getParentKey(),
-        comment.getKey().get(),
-        new GerritCallback<JavaScriptObject>() {
-          @Override
-          public void onSuccess(JavaScriptObject result) {
-            notifyDraftDelta(-1);
-            removeUI();
-          }
-
-          @Override
-          public void onFailure(final Throwable caught) {
-            text.setReadOnly(false);
-            text.setFocus(true);
-            save.setEnabled(true);
-            cancel.setEnabled(true);
-            discard.setEnabled(true);
-            super.onFailure(caught);
-          }
-        });
-  }
-
-  private void removeUI() {
-    CommentEditorContainer c = getContainer();
-    if (c != null) {
-      c.remove(this);
-    }
-  }
-
-  private CommentEditorContainer getContainer() {
-    Widget p = getParent();
-    while (p != null) {
-      if (p instanceof CommentEditorContainer) {
-        return (CommentEditorContainer) p;
-      }
-      p = p.getParent();
-    }
-    return null;
-  }
-
-  public static CommentInfo toInput(PatchLineComment c) {
-    CommentInfo i = CommentInfo.createObject().cast();
-    i.id(c.getKey().get());
-    i.path(c.getKey().getParentKey().get());
-    i.side(c.getSide() == 0 ? Side.PARENT : Side.REVISION);
-    if (c.getLine() > 0) {
-      i.line(c.getLine());
-    }
-    i.inReplyTo(c.getParentUuid());
-    i.message(c.getMessage());
-    return i;
-  }
-
-  public static PatchLineComment toComment(PatchSet.Id ps,
-      String path,
-      CommentInfo i) {
-    PatchLineComment p = new PatchLineComment(
-        new PatchLineComment.Key(
-            new Patch.Key(ps, path),
-            i.id()),
-        i.line(),
-        Gerrit.getUserAccount().getId(),
-        i.inReplyTo(),
-        i.updated());
-    p.setMessage(i.message());
-    p.setSide((short) (i.side() == Side.PARENT ? 0 : 1));
-    return p;
-  }
-}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/CommitMessageBlock.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/CommitMessageBlock.java
deleted file mode 100644
index f336382..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/CommitMessageBlock.java
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright (C) 2010 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.client.patches;
-
-import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.client.changes.StarredChanges;
-import com.google.gerrit.client.changes.Util;
-import com.google.gerrit.client.ui.ChangeLink;
-import com.google.gerrit.client.ui.CommentLinkProcessor;
-import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.dom.client.PreElement;
-import com.google.gwt.dom.client.Style.Display;
-import com.google.gwt.uibinder.client.UiBinder;
-import com.google.gwt.uibinder.client.UiField;
-import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.FlowPanel;
-import com.google.gwt.user.client.ui.HTMLPanel;
-import com.google.gwt.user.client.ui.SimplePanel;
-import com.google.gwtexpui.clippy.client.CopyableLabel;
-import com.google.gwtexpui.globalkey.client.KeyCommandSet;
-import com.google.gwtexpui.safehtml.client.SafeHtml;
-import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
-
-class CommitMessageBlock extends Composite {
-  interface Binder extends UiBinder<HTMLPanel, CommitMessageBlock> {}
-  private static final Binder uiBinder = GWT.create(Binder.class);
-
-  private KeyCommandSet keysAction;
-
-  @UiField
-  SimplePanel starPanel;
-  @UiField
-  FlowPanel permalinkPanel;
-  @UiField
-  PreElement commitSummaryPre;
-  @UiField
-  PreElement commitBodyPre;
-
-  CommitMessageBlock() {
-    initWidget(uiBinder.createAndBindUi(this));
-  }
-
-  CommitMessageBlock(KeyCommandSet keysAction) {
-    this.keysAction = keysAction;
-    initWidget(uiBinder.createAndBindUi(this));
-  }
-
-  void display(String commitMessage,
-      CommentLinkProcessor commentLinkProcessor) {
-    display(null, null, null, commitMessage, commentLinkProcessor);
-  }
-
-  void display(final PatchSet.Id patchSetId, final String revision,
-      Boolean starred, final String commitMessage,
-      CommentLinkProcessor commentLinkProcessor) {
-    starPanel.clear();
-    if (patchSetId != null && starred != null && Gerrit.isSignedIn()) {
-      Change.Id changeId = patchSetId.getParentKey();
-      StarredChanges.Icon star = StarredChanges.createIcon(changeId, starred);
-      star.setStyleName(Gerrit.RESOURCES.css().changeScreenStarIcon());
-      starPanel.add(star);
-
-      if (keysAction != null) {
-        keysAction.add(StarredChanges.newKeyCommand(star));
-      }
-    }
-
-    permalinkPanel.clear();
-    if (patchSetId != null && revision != null) {
-      final Change.Id changeId = patchSetId.getParentKey();
-      permalinkPanel.add(new ChangeLink(Util.C.changePermalink(), changeId));
-      permalinkPanel.add(new CopyableLabel(ChangeLink.permalink(changeId),
-          false));
-    }
-
-    String[] splitCommitMessage = commitMessage.split("\n", 2);
-
-    String commitSummary = splitCommitMessage[0];
-    String commitBody = "";
-    if (splitCommitMessage.length > 1) {
-      commitBody = splitCommitMessage[1];
-    }
-
-    // Linkify commit summary
-    SafeHtml commitSummaryLinkified = new SafeHtmlBuilder().append(commitSummary);
-    commitSummaryLinkified = commitSummaryLinkified.linkify();
-    commitSummaryLinkified = commentLinkProcessor.apply(commitSummaryLinkified);
-    commitSummaryPre.setInnerHTML(commitSummaryLinkified.asString());
-
-    // Hide commit body if there is no body
-    if (commitBody.trim().isEmpty()) {
-      commitBodyPre.getStyle().setDisplay(Display.NONE);
-    } else {
-      // Linkify commit body
-      SafeHtml commitBodyLinkified = new SafeHtmlBuilder().append(commitBody);
-      commitBodyLinkified = commitBodyLinkified.linkify();
-      commitBodyLinkified = commentLinkProcessor.apply(commitBodyLinkified);
-      commitBodyLinkified = commitBodyLinkified.replaceAll("\n\n", "<p></p>");
-      commitBodyLinkified = commitBodyLinkified.replaceAll("\n", "<br />");
-      commitBodyPre.setInnerHTML(commitBodyLinkified.asString());
-    }
-  }
-}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/CommitMessageBlock.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/CommitMessageBlock.ui.xml
deleted file mode 100644
index f1bf3de..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/CommitMessageBlock.ui.xml
+++ /dev/null
@@ -1,102 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-Copyright (C) 2012 The Android Open Source Project
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-
-<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
-    xmlns:g='urn:import:com.google.gwt.user.client.ui'>
-
-
-  <ui:with field='res' type='com.google.gerrit.client.GerritResources'/>
-  <ui:style gss='false'>
-    @eval selectionColor com.google.gerrit.client.Gerrit.getTheme().selectionColor;
-    @eval trimColor com.google.gerrit.client.Gerrit.getTheme().trimColor;
-    @eval backgroundColor com.google.gerrit.client.Gerrit.getTheme().backgroundColor;
-
-    .commitMessageTable {
-      border-collapse: separate;
-      border-spacing: 0;
-      margin-bottom: 10px;
-    }
-
-    .header {
-      background-color: trimColor;
-      white-space: nowrap;
-      color: textColor;
-      font-size: 10pt;
-      font-style: italic;
-      padding: 2px 6px 1px;
-    }
-
-    .contents {
-      border-bottom: 1px solid trimColor;
-      border-left: 1px solid trimColor;
-      border-right: 1px solid trimColor;
-      padding: 5px;
-    }
-
-    .contents span {
-      font-weight: bold;
-    }
-
-    .contents pre {
-      margin: 0;
-    }
-
-    .commitSummary {
-      font-weight: bold;
-    }
-
-    .commitBody p {
-      padding-top: 0px;
-    }
-
-    .starPanel {
-      float: left;
-    }
-
-    .boxTitle {
-      float: left;
-      margin-right: 10px;
-    }
-
-    .permalinkPanel {
-      float: right;
-    }
-
-    .permalinkPanel a {
-      float: left;
-    }
-
-    .permalinkPanel div {
-      display: inline;
-    }
-  </ui:style>
-
-  <g:HTMLPanel>
-    <table class='{style.commitMessageTable}'>
-      <tr><td class='{style.header}'>
-        <g:SimplePanel styleName='{style.starPanel}' ui:field='starPanel'></g:SimplePanel>
-        <div class='{style.boxTitle}'>Commit Message</div>
-        <g:FlowPanel styleName='{style.permalinkPanel}' ui:field='permalinkPanel'></g:FlowPanel>
-      </td></tr>
-      <tr><td class='{style.contents}'>
-        <pre class='{style.commitSummary} {res.css.changeScreenDescription}' ui:field='commitSummaryPre'/>
-        <pre class='{style.commitBody} {res.css.changeScreenDescription}' ui:field='commitBodyPre'/>
-      </td></tr>
-    </table>
-  </g:HTMLPanel>
-</ui:UiBinder>
-
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/HistoryTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/HistoryTable.java
deleted file mode 100644
index c4fc1b0..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/HistoryTable.java
+++ /dev/null
@@ -1,155 +0,0 @@
-// Copyright (C) 2009 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.client.patches;
-
-import com.google.gerrit.client.Dispatcher;
-import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.client.changes.Util;
-import com.google.gerrit.client.ui.FancyFlexTable;
-import com.google.gerrit.reviewdb.client.Patch;
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;
-import com.google.gwt.user.client.ui.HasHorizontalAlignment;
-import com.google.gwt.user.client.ui.RadioButton;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A table used to specify which two patch sets should be diff'ed.
- */
-class HistoryTable extends FancyFlexTable<Patch> {
-  private final UnifiedPatchScreen screen;
-  final List<HistoryRadio> all = new ArrayList<>();
-
-  HistoryTable(final UnifiedPatchScreen parent) {
-    setStyleName(Gerrit.RESOURCES.css().patchHistoryTable());
-    screen = parent;
-    table.setWidth("auto");
-    table.addStyleName(Gerrit.RESOURCES.css().changeTable());
-  }
-
-  void onClick(final HistoryRadio b) {
-    PatchSet.Id sideA = screen.idSideA;
-    PatchSet.Id sideB = screen.idSideB;
-    switch (b.file) {
-      case 0:
-        sideA = b.patchSetId;
-        break;
-      case 1:
-        sideB = b.patchSetId;
-        break;
-      default:
-        return;
-    }
-    enableAll(false);
-    Patch.Key k = new Patch.Key(sideB, screen.getPatchKey().get());
-    Gerrit.display(Dispatcher.toUnified(sideA, k));
-  }
-
-  void enableAll(final boolean on) {
-    for (final HistoryRadio a : all) {
-      a.setEnabled(on);
-    }
-  }
-
-  void display(final List<Patch> result) {
-    all.clear();
-    final FlexCellFormatter fmt = table.getFlexCellFormatter();
-    table.setText(0, 0, PatchUtil.C.patchHeaderPatchSet());
-    fmt.setStyleName(0, 0, Gerrit.RESOURCES.css().dataHeader());
-    table.setText(1, 0, PatchUtil.C.patchHeaderOld());
-    fmt.setStyleName(1, 0, Gerrit.RESOURCES.css().dataHeader());
-    table.setText(2, 0, PatchUtil.C.patchHeaderNew());
-    fmt.setStyleName(2, 0, Gerrit.RESOURCES.css().dataHeader());
-    table.setText(3, 0, Util.C.patchTableColumnComments());
-    fmt.setStyleName(3, 0, Gerrit.RESOURCES.css().dataHeader());
-
-    if (screen.getPatchSetDetail().getInfo().getParents().size() > 1) {
-      table.setText(0, 1, PatchUtil.C.patchBaseAutoMerge());
-    } else {
-      table.setText(0, 1, PatchUtil.C.patchBase());
-    }
-    fmt.setStyleName(0, 1, Gerrit.RESOURCES.css().dataCell());
-    fmt.addStyleName(0, 1, Gerrit.RESOURCES.css().topMostCell());
-    fmt.setStyleName(1, 1, Gerrit.RESOURCES.css().dataCell());
-    fmt.setStyleName(2, 1, Gerrit.RESOURCES.css().dataCell());
-    fmt.setStyleName(3, 1, Gerrit.RESOURCES.css().dataCell());
-
-    installRadio(1, 1, null, screen.idSideA, 0);
-
-    int col=2;
-    for (final Patch k : result) {
-      final PatchSet.Id psId = k.getKey().getParentKey();
-      table.setText(0, col, String.valueOf(psId.get()));
-      fmt.setStyleName(0, col, Gerrit.RESOURCES.css().patchHistoryTablePatchSetHeader());
-      fmt.addStyleName(0, col, Gerrit.RESOURCES.css().dataCell());
-      fmt.addStyleName(0, col, Gerrit.RESOURCES.css().topMostCell());
-
-      installRadio(1, col, psId, screen.idSideA, 0);
-      installRadio(2, col, psId, screen.idSideB, 1);
-
-      fmt.setStyleName(3, col, Gerrit.RESOURCES.css().dataCell());
-      if (k.getCommentCount() > 0) {
-        table.setText(3, col, Integer.toString(k.getCommentCount()));
-      }
-      col++;
-    }
-  }
-
-  private void installRadio(final int row, final int col, final PatchSet.Id psId,
-      final PatchSet.Id cur, final int file) {
-    final HistoryRadio b = new HistoryRadio(psId, file);
-    b.setValue(eq(cur, psId));
-
-    table.setWidget(row, col, b);
-    final FlexCellFormatter fmt = table.getFlexCellFormatter();
-    fmt.setHorizontalAlignment(row, col, HasHorizontalAlignment.ALIGN_CENTER);
-    fmt.setStyleName(row, col, Gerrit.RESOURCES.css().dataCell());
-    all.add(b);
-  }
-
-  private boolean eq(final PatchSet.Id cur, final PatchSet.Id psid) {
-    if (cur == null && psid == null) {
-      return true;
-    }
-    return psid != null && psid.equals(cur);
-  }
-
-  private class HistoryRadio extends RadioButton {
-    final PatchSet.Id patchSetId;
-    final int file;
-
-    HistoryRadio(final PatchSet.Id ps, final int f) {
-      super(String.valueOf(f));
-      sinkEvents(Event.ONCLICK);
-      patchSetId = ps;
-      file = f;
-    }
-
-    @Override
-    public void onBrowserEvent(final Event event) {
-      switch (DOM.eventGetType(event)) {
-        case Event.ONCLICK:
-          onClick(this);
-          break;
-        default:
-          super.onBrowserEvent(event);
-      }
-    }
-  }
-}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/NavLinks.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/NavLinks.java
deleted file mode 100644
index adfaa04..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/NavLinks.java
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright (C) 2010 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.client.patches;
-
-import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.client.changes.Util;
-import com.google.gerrit.client.info.WebLinkInfo;
-import com.google.gerrit.client.ui.ChangeLink;
-import com.google.gerrit.client.ui.InlineHyperlink;
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gwt.event.dom.client.KeyPressEvent;
-import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.FlowPanel;
-import com.google.gwt.user.client.ui.Grid;
-import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
-import com.google.gwt.user.client.ui.HasHorizontalAlignment;
-import com.google.gwt.user.client.ui.Label;
-import com.google.gwtexpui.globalkey.client.KeyCommand;
-import com.google.gwtexpui.globalkey.client.KeyCommandSet;
-import com.google.gwtexpui.safehtml.client.SafeHtml;
-
-import java.util.List;
-
-class NavLinks extends Composite {
-  public enum Nav {
-    PREV (0, '[', PatchUtil.C.previousFileHelp(), 0),
-    NEXT (4, ']', PatchUtil.C.nextFileHelp(), 1);
-
-    public int col;      // Table Cell column to display link in
-    public int key;      // key code shortcut to activate link
-    public String help;  // help string for '?' popup
-    public int cmd;      // index into cmds array
-
-    Nav(int c, int k, String h, int i) {
-      this.col = c;
-      this.key = k;
-      this.help = h;
-      this.cmd = i;
-    }
-  }
-
-  private final PatchSet.Id patchSetId;
-  private final KeyCommandSet keys;
-  private final Grid table;
-
-  private KeyCommand[] cmds = new KeyCommand[2];
-
-  NavLinks(KeyCommandSet kcs, PatchSet.Id forPatch) {
-    patchSetId = forPatch;
-    keys = kcs;
-    table = new Grid(1, 5);
-    initWidget(table);
-
-    final CellFormatter fmt = table.getCellFormatter();
-    table.setStyleName(Gerrit.RESOURCES.css().sideBySideScreenLinkTable());
-    fmt.setHorizontalAlignment(0, 0, HasHorizontalAlignment.ALIGN_LEFT);
-    fmt.setHorizontalAlignment(0, 1, HasHorizontalAlignment.ALIGN_CENTER);
-    fmt.setHorizontalAlignment(0, 2, HasHorizontalAlignment.ALIGN_RIGHT);
-    fmt.setHorizontalAlignment(0, 3, HasHorizontalAlignment.ALIGN_RIGHT);
-    fmt.setHorizontalAlignment(0, 4, HasHorizontalAlignment.ALIGN_RIGHT);
-
-    final ChangeLink up = new ChangeLink("", patchSetId);
-    SafeHtml.set(up, SafeHtml.asis(Util.C.upToChangeIconLink()));
-    table.setWidget(0, 1, up);
-  }
-
-  void display(int patchIndex, PatchTable fileList,
-      List<InlineHyperlink> links, List<WebLinkInfo> webLinks) {
-    if (fileList != null) {
-      Label fileCountLabel =
-          new Label(Gerrit.M.fileCount(patchIndex + 1, fileList.size()));
-      fileCountLabel.setStyleName(Gerrit.RESOURCES.css().nowrap());
-      table.setWidget(0, 3, fileCountLabel);
-      setupNav(Nav.PREV, fileList.getPreviousPatchLink(patchIndex));
-      setupNav(Nav.NEXT, fileList.getNextPatchLink(patchIndex));
-    } else {
-      setupNav(Nav.PREV, null);
-      setupNav(Nav.NEXT, null);
-    }
-
-    FlowPanel linkPanel = new FlowPanel();
-    linkPanel.setStyleName(Gerrit.RESOURCES.css().linkPanel());
-    for (InlineHyperlink link : links) {
-      linkPanel.add(link);
-    }
-    for (WebLinkInfo webLink : webLinks) {
-      linkPanel.add(webLink.toAnchor());
-    }
-    table.setWidget(0, 2, linkPanel);
-  }
-
-  protected void setupNav(final Nav nav, final InlineHyperlink link) {
-
-    /* setup the cells */
-    if (link != null) {
-      link.addStyleName(Gerrit.RESOURCES.css().nowrap());
-      table.setWidget(0, nav.col, link);
-    } else {
-      table.clearCell(0, nav.col);
-    }
-
-    /* setup the keys */
-    if (keys != null) {
-
-      if (cmds[nav.cmd] != null) {
-        keys.remove(cmds[nav.cmd]);
-      }
-
-      if (link != null) {
-        cmds[nav.cmd] = new KeyCommand(0, nav.key, nav.help) {
-          @Override
-          public void onKeyPress(KeyPressEvent event) {
-            link.go();
-          }
-        };
-      } else {
-        cmds[nav.cmd] = new UpToChangeCommand(patchSetId, 0, nav.key);
-      }
-
-      keys.add(cmds[nav.cmd]);
-    }
-  }
-}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchBrowserPopup.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchBrowserPopup.java
deleted file mode 100644
index 2962fb1..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchBrowserPopup.java
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright (C) 2009 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.client.patches;
-
-import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.client.changes.Util;
-import com.google.gerrit.reviewdb.client.Patch;
-import com.google.gwt.event.logical.shared.ResizeEvent;
-import com.google.gwt.event.logical.shared.ResizeHandler;
-import com.google.gwt.event.shared.HandlerRegistration;
-import com.google.gwt.user.client.Command;
-import com.google.gwt.user.client.Window;
-import com.google.gwt.user.client.ui.DialogBox;
-import com.google.gwt.user.client.ui.FlowPanel;
-import com.google.gwt.user.client.ui.PopupPanel.PositionCallback;
-import com.google.gwt.user.client.ui.ScrollPanel;
-import com.google.gwtexpui.globalkey.client.GlobalKey;
-import com.google.gwtexpui.globalkey.client.HidePopupPanelCommand;
-
-class PatchBrowserPopup extends DialogBox implements
-    PositionCallback, ResizeHandler {
-  private final Patch.Key callerKey;
-  private final PatchTable fileList;
-  private final ScrollPanel sp;
-  private HandlerRegistration regWindowResize;
-
-  PatchBrowserPopup(final Patch.Key pk, final PatchTable fl) {
-    super(true/* autohide */, false/* modal */);
-
-    callerKey = pk;
-    fileList = fl;
-    sp = new ScrollPanel(fileList);
-
-    final FlowPanel body = new FlowPanel();
-    body.setStyleName(Gerrit.RESOURCES.css().patchBrowserPopupBody());
-    body.add(sp);
-
-    setText(Util.M.patchSetHeader(callerKey.getParentKey().get()));
-    setWidget(body);
-    addStyleName(Gerrit.RESOURCES.css().patchBrowserPopup());
-  }
-
-  @Override
-  public void setPosition(final int myWidth, int myHeight) {
-    final int dLeft = (Window.getClientWidth() - myWidth) >> 1;
-    final int cHeight = Window.getClientHeight();
-    final int cHeight2 = 2 * cHeight / 3;
-    final int sLeft = Window.getScrollLeft();
-    final int sTop = Window.getScrollTop();
-
-    if (myHeight > cHeight2) {
-      sp.setHeight((cHeight2 - 50) + "px");
-      myHeight = getOffsetHeight();
-    }
-    setPopupPosition(sLeft + dLeft, (sTop + cHeight) - (myHeight + 10));
-  }
-
-  @Override
-  public void onResize(final ResizeEvent event) {
-    sp.setWidth((Window.getClientWidth() - 60) + "px");
-    setPosition(getOffsetWidth(), getOffsetHeight());
-  }
-
-  @Override
-  public void hide() {
-    if (regWindowResize != null) {
-      regWindowResize.removeHandler();
-      regWindowResize = null;
-    }
-    super.hide();
-  }
-
-  @Override
-  public void show() {
-    super.show();
-    if (regWindowResize == null) {
-      regWindowResize = Window.addResizeHandler(this);
-    }
-
-    GlobalKey.dialog(this);
-    GlobalKey.addApplication(this, new HidePopupPanelCommand(0, 'f', this));
-
-    if (!fileList.isLoaded()) {
-      fileList.onTableLoaded(new Command() {
-        @Override
-        public void execute() {
-          sp.setHeight("");
-          setPosition(getOffsetWidth(), getOffsetHeight());
-          fileList.setRegisterKeys(true);
-          fileList.movePointerTo(callerKey);
-        }
-      });
-    }
-  }
-
-  public void open() {
-    if (!fileList.isLoaded()) {
-      sp.setHeight("22px");
-    }
-    sp.setWidth((Window.getClientWidth() - 60) + "px");
-    setPopupPositionAndShow(this);
-    if (fileList.isLoaded()) {
-      fileList.setRegisterKeys(true);
-      fileList.movePointerTo(callerKey);
-    }
-  }
-}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java
index 422a4dd..0bc42cb 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java
@@ -17,49 +17,25 @@
 import com.google.gwt.i18n.client.Constants;
 
 public interface PatchConstants extends Constants {
-  String draft();
-
-  String buttonReply();
-  String buttonEdit();
-  String buttonSave();
-  String buttonCancel();
-  String buttonDiscard();
-
-  String noDifference();
   String patchBase();
-  String patchBaseAutoMerge();
-  String patchHeaderPatchSet();
-  String patchHeaderOld();
-  String patchHeaderNew();
   String patchSet();
 
-  String patchHistoryTitle();
-  String disabledOnLargeFiles();
-  String intralineFailure();
-  String intralineTimeout();
-  String illegalNumberOfColumns();
-
   String upToChange();
   String openReply();
   String linePrev();
   String lineNext();
   String chunkPrev();
   String chunkNext();
-  String chunkPrev2();
-  String chunkNext2();
   String commentPrev();
   String commentNext();
   String focusSideA();
   String focusSideB();
-  String fileList();
   String expandComment();
   String expandAllCommentsOnCurrentLine();
   String toggleSideA();
   String toggleIntraline();
   String showPreferences();
 
-  String openEditScreen();
-
   String toggleReviewed();
   String markAsReviewedAndGoToNext();
 
@@ -76,22 +52,12 @@
   String previousFileHelp();
   String nextFileHelp();
 
-  String reviewedAnd();
-  String next();
   String download();
   String edit();
   String addFileCommentToolTip();
-  String addFileCommentByDoubleClick();
 
-  String buttonReplyDone();
   String cannedReplyDone();
 
-  String fileTypeSymlink();
-  String fileTypeGitlink();
-
-  String patchSkipRegionStart();
-  String patchSkipRegionEnd();
-
   String sideBySideDiff();
   String unifiedDiff();
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties
index aa6177b..9f7c62e 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties
@@ -1,46 +1,24 @@
-draft = (Draft)
-
-buttonReply = Reply ...
-buttonReplyDone = Reply 'Done'
 cannedReplyDone = Done
-buttonEdit = Edit
-buttonSave = Save
-buttonCancel = Cancel
-buttonDiscard = Discard
 
-noDifference = No Differences
 patchBase = Base
-patchBaseAutoMerge = Auto Merge
-patchHeaderPatchSet = Patch Set
-patchHeaderOld = Old Version
-patchHeaderNew = New Version
-patchHistoryTitle = Patch History
 patchSet = Patch Set
-disabledOnLargeFiles = Disabled on very large source files.
-intralineFailure = Intraline difference not available due to server error.
-intralineTimeout = Intraline difference not available due to timeout.
-illegalNumberOfColumns = The number of columns cannot be zero or negative
 
 upToChange = Up to change
 openReply = Reply and score
 linePrev = Previous line
 lineNext = Next line
-chunkPrev = Previous diff chunk or comment
-chunkNext = Next diff chunk or comment
-chunkPrev2 = Previous diff chunk
-chunkNext2 = Next diff chunk or search result
+chunkPrev = Previous diff chunk
+chunkNext = Next diff chunk or search result
 commentPrev = Previous comment
 commentNext = Next comment
 focusSideA = Focus left side
 focusSideB = Focus right side
-fileList = Browse files in patch set
 expandComment = Expand or collapse comment
 expandAllCommentsOnCurrentLine = Expand or collapse all comments on current line
 toggleSideA = Toggle left side
 toggleIntraline = Toggle intraline difference
 showPreferences = Show diff preferences
 
-openEditScreen = Edit file in browser
 toggleReviewed = Toggle the reviewed flag
 markAsReviewedAndGoToNext = Mark patch as reviewed and go to next unreviewed patch
 
@@ -57,18 +35,9 @@
 previousFileHelp = Previous file
 nextFileHelp = Next file
 
-reviewedAnd = Reviewed &
-next = next
 download = Download
 edit = Edit
 addFileCommentToolTip = Click to add file comment
-addFileCommentByDoubleClick = Double click to add file comment
-
-fileTypeSymlink = Type: Symbolic Link
-fileTypeGitlink = Type: Git Commit in Subproject
-
-patchSkipRegionStart = ... skipped
-patchSkipRegionEnd = common lines ...
 
 sideBySideDiff = Side-by-side diff
 unifiedDiff = Unified diff
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchLine.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchLine.java
deleted file mode 100644
index 4863af2..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchLine.java
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (C) 2008 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.client.patches;
-
-class PatchLine {
-  static enum Type {
-    DELETE, INSERT, REPLACE, CONTEXT
-  }
-
-  private PatchLine.Type type;
-  private int lineA;
-  private int lineB;
-
-  PatchLine(final PatchLine.Type t, final int a, final int b) {
-    type = t;
-    lineA = a;
-    lineB = b;
-  }
-
-  PatchLine.Type getType() {
-    return type;
-  }
-
-  int getLineA() {
-    return lineA;
-  }
-
-  int getLineB() {
-    return lineB;
-  }
-}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchMessages.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchMessages.java
index 822eff7..aaab1c9 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchMessages.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchMessages.java
@@ -16,12 +16,9 @@
 
 import com.google.gwt.i18n.client.Messages;
 
-import java.util.Date;
-
 public interface PatchMessages extends Messages {
   String expandBefore(int cnt);
   String expandAfter(int cnt);
-  String draftSaved(Date when);
   String patchSkipRegion(String lineNumber);
   String fileNameWithShortcutKey(String file, String key);
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchMessages.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchMessages.properties
index fbb7d08..8dcebdc 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchMessages.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchMessages.properties
@@ -1,5 +1,4 @@
 expandBefore = +{0}&#x21e7;
 expandAfter = +{0}&#x21e9;
-draftSaved = Draft saved at {0,time,short}
 patchSkipRegion = ... skipped {0} common lines ...
 fileNameWithShortcutKey = {0} (Shortcut: {1})
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchMessages_en.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchMessages_en.properties
index e24333e..8dcebdc 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchMessages_en.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchMessages_en.properties
@@ -1,3 +1,4 @@
 expandBefore = +{0}&#x21e7;
 expandAfter = +{0}&#x21e9;
 patchSkipRegion = ... skipped {0} common lines ...
+fileNameWithShortcutKey = {0} (Shortcut: {1})
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.java
deleted file mode 100644
index b7ba64b..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.java
+++ /dev/null
@@ -1,347 +0,0 @@
-// Copyright (C) 2010 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.client.patches;
-
-import com.google.gerrit.client.ErrorDialog;
-import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.client.account.Util;
-import com.google.gerrit.client.rpc.GerritCallback;
-import com.google.gerrit.client.ui.ListenableAccountDiffPreference;
-import com.google.gerrit.client.ui.NpIntTextBox;
-import com.google.gerrit.extensions.client.DiffPreferencesInfo;
-import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.dom.client.NodeList;
-import com.google.gwt.dom.client.OptionElement;
-import com.google.gwt.dom.client.SelectElement;
-import com.google.gwt.event.dom.client.ClickEvent;
-import com.google.gwt.event.dom.client.KeyCodes;
-import com.google.gwt.event.dom.client.KeyPressEvent;
-import com.google.gwt.event.dom.client.KeyPressHandler;
-import com.google.gwt.uibinder.client.UiBinder;
-import com.google.gwt.uibinder.client.UiField;
-import com.google.gwt.uibinder.client.UiHandler;
-import com.google.gwt.user.client.ui.Button;
-import com.google.gwt.user.client.ui.CheckBox;
-import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.FocusWidget;
-import com.google.gwt.user.client.ui.HasWidgets;
-import com.google.gwt.user.client.ui.ListBox;
-import com.google.gwt.user.client.ui.Widget;
-import com.google.gwtjsonrpc.common.VoidResult;
-
-public class PatchScriptSettingsPanel extends Composite {
-  private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
-
-  interface MyUiBinder extends UiBinder<Widget, PatchScriptSettingsPanel> {
-  }
-
-  private final ListenableAccountDiffPreference listenablePrefs;
-  private boolean enableIntralineDifference = true;
-  private boolean enableSmallFileFeatures = true;
-
-  @UiField
-  ListBox ignoreWhitespace;
-
-  @UiField
-  NpIntTextBox tabWidth;
-
-  @UiField
-  NpIntTextBox colWidth;
-
-  @UiField
-  CheckBox syntaxHighlighting;
-
-  @UiField
-  CheckBox intralineDifference;
-
-  @UiField
-  ListBox context;
-
-  @UiField
-  CheckBox whitespaceErrors;
-
-  @UiField
-  CheckBox showLineEndings;
-
-  @UiField
-  CheckBox showTabs;
-
-  @UiField
-  CheckBox manualReview;
-
-  @UiField
-  CheckBox skipDeleted;
-
-  @UiField
-  CheckBox skipUncommented;
-
-  @UiField
-  CheckBox expandAllComments;
-
-  @UiField
-  CheckBox retainHeader;
-
-  @UiField
-  Button update;
-
-  @UiField
-  Button save;
-
-  /**
-   * Counts +1 for every setEnabled(true) and -1 for every setEnabled(false)
-   *
-   * The purpose is to prevent enabling widgets too early. It might happen that
-   * setEnabled(false) is called from this class and from an event handler
-   * of ValueChangeEvent in another class. The first setEnabled(true) would then
-   * enable widgets too early i.e. before the second setEnabled(true) is called.
-   *
-   * With this counter the setEnabled(true) will enable widgets only when
-   * setEnabledCounter == 0. Until it is less than zero setEnabled(true) will
-   * not enable the widgets.
-   */
-  private int setEnabledCounter;
-
-  public PatchScriptSettingsPanel(ListenableAccountDiffPreference prefs) {
-    listenablePrefs = prefs;
-    initWidget(uiBinder.createAndBindUi(this));
-    initIgnoreWhitespace(ignoreWhitespace);
-    initContext(context);
-    if (!Gerrit.isSignedIn()) {
-      save.setVisible(false);
-    }
-
-    KeyPressHandler onEnter = new KeyPressHandler() {
-      @Override
-      public void onKeyPress(KeyPressEvent event) {
-        if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER) {
-          save();
-        }
-      }
-    };
-    tabWidth.addKeyPressHandler(onEnter);
-    colWidth.addKeyPressHandler(onEnter);
-
-    display();
-  }
-
-  public void setEnabled(final boolean on) {
-    if (on) {
-      setEnabledCounter++;
-    } else {
-      setEnabledCounter--;
-    }
-    if (on && setEnabledCounter == 0 || !on) {
-      for (Widget w : (HasWidgets) getWidget()) {
-        if (w instanceof FocusWidget) {
-          ((FocusWidget) w).setEnabled(on);
-        }
-      }
-      toggleEnabledStatus(on);
-    }
-  }
-
-  public void setEnableSmallFileFeatures(final boolean on) {
-    enableSmallFileFeatures = on;
-    if (enableSmallFileFeatures) {
-      syntaxHighlighting.setValue(getValue().syntaxHighlighting);
-    } else {
-      syntaxHighlighting.setValue(false);
-    }
-
-    NodeList<OptionElement> options =
-        context.getElement().<SelectElement>cast().getOptions();
-    // WHOLE_FILE_CONTEXT is the last option in the list.
-    int lastIndex = options.getLength() - 1;
-    OptionElement currOption = options.getItem(lastIndex);
-    if (enableSmallFileFeatures) {
-      currOption.setDisabled(false);
-    } else {
-      currOption.setDisabled(true);
-      if (context.getSelectedIndex() == lastIndex) {
-        // Select the next longest context from WHOLE_FILE_CONTEXT
-        context.setSelectedIndex(lastIndex - 1);
-      }
-    }
-    toggleEnabledStatus(save.isEnabled());
-  }
-
-  public void setEnableIntralineDifference(final boolean on) {
-    enableIntralineDifference = on;
-    if (enableIntralineDifference) {
-      intralineDifference.setValue(getValue().intralineDifference);
-    } else {
-      intralineDifference.setValue(false);
-    }
-    toggleEnabledStatus(save.isEnabled());
-  }
-
-  private void toggleEnabledStatus(final boolean on) {
-    intralineDifference.setEnabled(on & enableIntralineDifference);
-    syntaxHighlighting.setEnabled(on & enableSmallFileFeatures);
-
-    final String title =
-        enableSmallFileFeatures ? null : PatchUtil.C.disabledOnLargeFiles();
-    syntaxHighlighting.setTitle(title);
-  }
-
-  public DiffPreferencesInfo getValue() {
-    return listenablePrefs.get();
-  }
-
-  public void setValue(final DiffPreferencesInfo dp) {
-    listenablePrefs.set(dp);
-    display();
-  }
-
-  protected void display() {
-    final DiffPreferencesInfo dp = getValue();
-    setIgnoreWhitespace(dp.ignoreWhitespace);
-    if (enableSmallFileFeatures) {
-      syntaxHighlighting.setValue(dp.syntaxHighlighting);
-    } else {
-      syntaxHighlighting.setValue(false);
-    }
-    setContext(dp.context);
-
-    tabWidth.setIntValue(dp.tabSize);
-    colWidth.setIntValue(dp.lineLength);
-    intralineDifference.setValue(dp.intralineDifference);
-    whitespaceErrors.setValue(dp.showWhitespaceErrors);
-    showLineEndings.setValue(dp.showLineEndings);
-    showTabs.setValue(dp.showTabs);
-    skipDeleted.setValue(dp.skipDeleted);
-    skipUncommented.setValue(dp.skipUncommented);
-    expandAllComments.setValue(dp.expandAllComments);
-    retainHeader.setValue(dp.retainHeader);
-    manualReview.setValue(dp.manualReview);
-  }
-
-  @UiHandler("update")
-  void onUpdate(@SuppressWarnings("unused") ClickEvent event) {
-    update();
-  }
-
-  @UiHandler("save")
-  void onSave(@SuppressWarnings("unused") ClickEvent event) {
-    save();
-  }
-
-  private void update() {
-    if (colWidth.getIntValue() <= 0) {
-      new ErrorDialog(PatchUtil.C.illegalNumberOfColumns()).center();
-      return;
-    }
-    DiffPreferencesInfo dp = getValue();
-    dp.ignoreWhitespace = getIgnoreWhitespace();
-    dp.context = getContext();
-    dp.tabSize = tabWidth.getIntValue();
-    dp.lineLength = colWidth.getIntValue();
-    dp.syntaxHighlighting = syntaxHighlighting.getValue();
-    dp.intralineDifference = intralineDifference.getValue();
-    dp.showWhitespaceErrors = whitespaceErrors.getValue();
-    dp.showLineEndings = showLineEndings.getValue();
-    dp.showTabs = showTabs.getValue();
-    dp.skipDeleted = skipDeleted.getValue();
-    dp.skipUncommented = skipUncommented.getValue();
-    dp.expandAllComments = expandAllComments.getValue();
-    dp.retainHeader = retainHeader.getValue();
-    dp.manualReview = manualReview.getValue();
-
-    listenablePrefs.set(dp);
-  }
-
-  private void save() {
-    update();
-    if (Gerrit.isSignedIn()) {
-      persistDiffPreferences();
-    }
-  }
-
-  private void persistDiffPreferences() {
-    setEnabled(false);
-    listenablePrefs.save(new GerritCallback<VoidResult>() {
-      @Override
-      public void onSuccess(VoidResult result) {
-        setEnabled(true);
-      }
-
-      @Override
-      public void onFailure(Throwable caught) {
-        setEnabled(true);
-      }
-    });
-  }
-
-  private void initIgnoreWhitespace(ListBox ws) {
-    ws.addItem(PatchUtil.C.whitespaceIGNORE_NONE(), //
-        Whitespace.IGNORE_NONE.name());
-    ws.addItem(PatchUtil.C.whitespaceIGNORE_TRAILING(), //
-        Whitespace.IGNORE_TRAILING.name());
-    ws.addItem(PatchUtil.C.whitespaceIGNORE_LEADING_AND_TRAILING(), //
-        Whitespace.IGNORE_LEADING_AND_TRAILING.name());
-    ws.addItem(PatchUtil.C.whitespaceIGNORE_ALL(), //
-        Whitespace.IGNORE_ALL.name());
-  }
-
-  private void initContext(ListBox context) {
-    for (final short v : DiffPreferencesInfo.CONTEXT_CHOICES) {
-      final String label;
-      if (v == DiffPreferencesInfo.WHOLE_FILE_CONTEXT) {
-        label = Util.C.contextWholeFile();
-      } else {
-        label = Util.M.lines(v);
-      }
-      context.addItem(label, String.valueOf(v));
-    }
-  }
-
-  private Whitespace getIgnoreWhitespace() {
-    final int sel = ignoreWhitespace.getSelectedIndex();
-    if (0 <= sel) {
-      return Whitespace.valueOf(ignoreWhitespace.getValue(sel));
-    }
-    return getValue().ignoreWhitespace;
-  }
-
-  private void setIgnoreWhitespace(Whitespace s) {
-    for (int i = 0; i < ignoreWhitespace.getItemCount(); i++) {
-      if (ignoreWhitespace.getValue(i).equals(s.name())) {
-        ignoreWhitespace.setSelectedIndex(i);
-        return;
-      }
-    }
-    ignoreWhitespace.setSelectedIndex(0);
-  }
-
-  private int getContext() {
-    final int sel = context.getSelectedIndex();
-    if (0 <= sel) {
-      return Short.parseShort(context.getValue(sel));
-    }
-    return getValue().context;
-  }
-
-  private void setContext(int ctx) {
-    String v = String.valueOf(ctx);
-    for (int i = 0; i < context.getItemCount(); i++) {
-      if (context.getValue(i).equals(v)) {
-        context.setSelectedIndex(i);
-        return;
-      }
-    }
-    context.setSelectedIndex(0);
-  }
-}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.ui.xml
deleted file mode 100644
index 5164302..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.ui.xml
+++ /dev/null
@@ -1,209 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-Copyright (C) 2010 The Android Open Source Project
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-<ui:UiBinder
-  xmlns:ui='urn:ui:com.google.gwt.uibinder'
-  xmlns:g='urn:import:com.google.gwt.user.client.ui'
-  xmlns:my='urn:import:com.google.gerrit.client.ui'
-  ui:generateFormat='com.google.gwt.i18n.rebind.format.PropertiesFormat'
-  ui:generateKeys='com.google.gwt.i18n.rebind.keygen.MD5KeyGenerator'
-  ui:generateLocales='default,en'
-  >
-<ui:style gss='false'>
-  @external .gwt-TextBox;
-  @external .gwt-ListBox;
-
-  @def fontSize 8pt;
-
-  .controls {
-    border: none;
-    border-collapse: separate;
-    border-spacing: 0;
-  }
-
-  .controls td {
-    font-size: fontSize;
-    padding: 0;
-    white-space: nowrap;
-  }
-
-  .controls .gwt-TextBox {
-    font-size: fontSize;
-    padding: 0;
-    text-align: right;
-  }
-
-  .controls .gwt-ListBox {
-    font-size: fontSize;
-    padding: 0;
-    margin-right: 1em;
-  }
-
-  .updateButton {
-    margin-left: 1em;
-    margin-right: 1em;
-    font-size: fontSize;
-  }
-</ui:style>
-
-<g:HTMLPanel>
-<table class='{style.controls}'>
-  <tr valign='top'>
-    <ui:msg>
-      <td align='right'>Ignore Whitespace:</td>
-      <td align='right'>
-        <g:ListBox
-          ui:field='ignoreWhitespace'
-          visibleItemCount='1'
-          tabIndex='1'/>
-      </td>
-    </ui:msg>
-
-    <td align='right'>
-      <ui:msg>Tab Width:
-      <my:NpIntTextBox
-        ui:field='tabWidth'
-        width='2em'
-        visibleLength='2'
-        maxLength='2'
-        tabIndex='3'/>
-      </ui:msg>
-    </td>
-
-    <td rowspan='2'>
-      <g:CheckBox
-          ui:field='syntaxHighlighting'
-          text='Syntax Coloring'
-          tabIndex='5'>
-        <ui:attribute name='text'/>
-      </g:CheckBox>
-      <br/>
-      <g:CheckBox
-          ui:field='intralineDifference'
-          text='Intraline Difference'
-          tabIndex='6'>
-        <ui:attribute name='text'/>
-      </g:CheckBox>
-    </td>
-
-    <td rowspan='2'>
-      <g:CheckBox
-          ui:field='whitespaceErrors'
-          text='Whitespace Errors'
-          tabIndex='7'>
-        <ui:attribute name='text'/>
-      </g:CheckBox>
-      <br/>
-      <g:CheckBox
-          ui:field='showLineEndings'
-          text='Show Line Endings'
-          tabIndex='8'>
-        <ui:attribute name='text'/>
-      </g:CheckBox>
-    </td>
-
-    <td rowspan='2'>
-      <g:CheckBox
-          ui:field='showTabs'
-          text='Show Tabs'
-          tabIndex='9'>
-        <ui:attribute name='text'/>
-      </g:CheckBox>
-      <br/>
-      <g:CheckBox
-          ui:field='expandAllComments'
-          text='Expand All Comments'
-          tabIndex='10'>
-        <ui:attribute name='text'/>
-      </g:CheckBox>
-    </td>
-
-    <td rowspan='2'>
-      <g:CheckBox
-          ui:field='retainHeader'
-          text='Retain Header On File Switch'
-          tabIndex='11'>
-        <ui:attribute name='text'/>
-      </g:CheckBox>
-      <br/>
-      <g:CheckBox
-          ui:field='skipUncommented'
-          text='Skip Uncommented Files'
-          tabIndex='12'>
-        <ui:attribute name='text'/>
-      </g:CheckBox>
-    </td>
-
-    <td valign='bottom' rowspan='2'>
-      <g:CheckBox
-          ui:field='skipDeleted'
-          text='Skip Deleted Files'
-          tabIndex='13'>
-        <ui:attribute name='text'/>
-      </g:CheckBox>
-      <br/>
-      <g:CheckBox
-          ui:field='manualReview'
-          text='Manual Review'
-          tabIndex='14'>
-        <ui:attribute name='text'/>
-      </g:CheckBox>
-    </td>
-
-    <td rowspan='2'>
-      <br/>
-      <g:Button
-          ui:field='update'
-          text='Update'
-          styleName='{style.updateButton}'
-          tabIndex='15'>
-        <ui:attribute name='text'/>
-      </g:Button>
-      <g:Button
-          ui:field='save'
-          text='Save'
-          styleName='{style.updateButton}'
-          tabIndex='16'>
-        <ui:attribute name='text'/>
-      </g:Button>
-    </td>
-  </tr>
-
-  <tr valign='top'>
-    <ui:msg>
-      <td align='right'>Context:</td>
-      <td align='right'>
-        <g:ListBox
-            ui:field='context'
-            visibleItemCount='1'
-            tabIndex='2'/>
-      </td>
-    </ui:msg>
-
-    <td align='right'>
-      <ui:msg>Columns:
-      <my:NpIntTextBox
-        ui:field='colWidth'
-        width='2.5em'
-        visibleLength='3'
-        maxLength='3'
-        tabIndex='4'/>
-      </ui:msg>
-    </td>
-  </tr>
-</table>
-</g:HTMLPanel>
-</ui:UiBinder>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.java
deleted file mode 100644
index 6762383..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.java
+++ /dev/null
@@ -1,188 +0,0 @@
-// Copyright (C) 2012 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.client.patches;
-
-import com.google.gerrit.client.Dispatcher;
-import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.common.data.PatchScript;
-import com.google.gerrit.common.data.PatchSetDetail;
-import com.google.gerrit.reviewdb.client.Patch;
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.event.dom.client.ClickEvent;
-import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.event.dom.client.DoubleClickEvent;
-import com.google.gwt.event.dom.client.DoubleClickHandler;
-import com.google.gwt.resources.client.CssResource;
-import com.google.gwt.uibinder.client.UiBinder;
-import com.google.gwt.uibinder.client.UiField;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.ui.Anchor;
-import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.HTMLPanel;
-import com.google.gwt.user.client.ui.Image;
-import com.google.gwt.user.client.ui.Label;
-import com.google.gwtorm.client.KeyUtil;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class PatchSetSelectBox extends Composite {
-  interface Binder extends UiBinder<HTMLPanel, PatchSetSelectBox> {}
-  private static final Binder uiBinder = GWT.create(Binder.class);
-
-  interface BoxStyle extends CssResource {
-    String selected();
-    String hidden();
-    String sideMarker();
-    String patchSetLabel();
-  }
-
-  public enum Side {
-    A, B
-  }
-
-  PatchScript script;
-  Patch.Key patchKey;
-  PatchSet.Id idSideA;
-  PatchSet.Id idSideB;
-  PatchSet.Id idActive;
-  Side side;
-  Map<Integer, Anchor> links;
-  private Label patchSet;
-
-  @UiField
-  HTMLPanel linkPanel;
-
-  @UiField
-  BoxStyle style;
-
-  public PatchSetSelectBox(Side side) {
-    this.side = side;
-
-    initWidget(uiBinder.createAndBindUi(this));
-  }
-
-  public void display(final PatchSetDetail detail, final PatchScript script,
-      Patch.Key key, PatchSet.Id idSideA, PatchSet.Id idSideB) {
-    this.script = script;
-    this.patchKey = key;
-    this.idSideA = idSideA;
-    this.idSideB = idSideB;
-    this.idActive = (side == Side.A) ? idSideA : idSideB;
-    this.links = new HashMap<>();
-
-    linkPanel.clear();
-
-    if (isFileOrCommitMessage()) {
-      linkPanel.setTitle(PatchUtil.C.addFileCommentByDoubleClick());
-    }
-
-    patchSet = new Label(PatchUtil.C.patchSet());
-    patchSet.addStyleName(style.patchSetLabel());
-    linkPanel.add(patchSet);
-
-    Label sideMarker = new Label((side == Side.A) ? "(-)" : "(+)");
-    sideMarker.addStyleName(style.sideMarker());
-    linkPanel.add(sideMarker);
-
-    Anchor baseLink;
-    if (detail.getInfo().getParents().size() > 1) {
-      baseLink = createLink(PatchUtil.C.patchBaseAutoMerge(), null);
-    } else {
-      baseLink = createLink(PatchUtil.C.patchBase(), null);
-    }
-
-    links.put(0, baseLink);
-    linkPanel.add(baseLink);
-
-    if (side == Side.B) {
-      links.get(0).setStyleName(style.hidden());
-    }
-
-    for (Patch patch : script.getHistory()) {
-      PatchSet.Id psId = patch.getKey().getParentKey();
-      Anchor anchor = createLink(psId.getId(), psId);
-      links.put(psId.get(), anchor);
-      linkPanel.add(anchor);
-    }
-
-    if (idActive == null && side == Side.A) {
-      links.get(0).setStyleName(style.selected());
-    } else if (idActive != null) {
-      links.get(idActive.get()).setStyleName(style.selected());
-    }
-
-    Anchor downloadLink = createDownloadLink();
-    if (downloadLink != null) {
-      linkPanel.add(downloadLink);
-    }
-  }
-
-  public void addDoubleClickHandler(DoubleClickHandler handler) {
-    linkPanel.sinkEvents(Event.ONDBLCLICK);
-    linkPanel.addHandler(handler, DoubleClickEvent.getType());
-    patchSet.addDoubleClickHandler(handler);
-  }
-
-  private Anchor createLink(String label, final PatchSet.Id id) {
-    final Anchor anchor = new Anchor(label);
-    anchor.addClickHandler(new ClickHandler() {
-      @Override
-      public void onClick(ClickEvent event) {
-        if (side == Side.A) {
-          idSideA = id;
-        } else {
-          idSideB = id;
-        }
-
-        Patch.Key keySideB = new Patch.Key(idSideB, patchKey.get());
-        Gerrit.display(Dispatcher.toUnified(idSideA, keySideB));
-      }
-    });
-    return anchor;
-  }
-
-  public boolean isFileOrCommitMessage() {
-    return !((side == Side.A && 0 >= script.getA().size()) || //
-    (side == Side.B && 0 >= script.getB().size()));
-  }
-
-  private Anchor createDownloadLink() {
-    boolean isCommitMessage = Patch.COMMIT_MSG.equals(script.getNewName());
-    if (isCommitMessage || //
-        (side == Side.A && 0 >= script.getA().size()) || //
-        (side == Side.B && 0 >= script.getB().size())) {
-      return null;
-    }
-
-    Patch.Key key = (idActive == null) ? //
-        patchKey : (new Patch.Key(idActive, patchKey.get()));
-
-    String sideURL = (idActive == null) ? "1" : "0";
-    final String base = GWT.getHostPageBaseURL() + "cat/";
-
-    Image image = new Image(Gerrit.RESOURCES.downloadIcon());
-
-    final Anchor anchor = new Anchor();
-    anchor.setHref(base + KeyUtil.encode(key.toString()) + "^" + sideURL);
-    anchor.setTitle(PatchUtil.C.download());
-    DOM.insertBefore(anchor.getElement(), image.getElement(),
-        DOM.getFirstChild(anchor.getElement()));
-
-    return anchor;
-  }
-}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.ui.xml
deleted file mode 100644
index 8977876..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.ui.xml
+++ /dev/null
@@ -1,67 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-Copyright (C) 2012 The Android Open Source Project
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-
-<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
-    xmlns:g='urn:import:com.google.gwt.user.client.ui'>
-  <ui:with field='res' type='com.google.gerrit.client.GerritResources'/>
-  <ui:style gss='false' type='com.google.gerrit.client.patches.PatchSetSelectBox.BoxStyle'>
-    @eval selectionColor com.google.gerrit.client.Gerrit.getTheme().selectionColor;
-    @eval backgroundColor com.google.gerrit.client.Gerrit.getTheme().backgroundColor;
-
-    .linkPanel {
-      font-size: 12px;
-      white-space: normal;
-    }
-
-    .linkPanel > div {
-      padding-left: 3px;
-      padding-right: 3px;
-      vertical-align: middle;
-      display: inline-block;
-    }
-
-    .patchSetLabel {
-      font-weight: bold;
-    }
-
-    .sideMarker {
-      font-family: monospace;
-    }
-
-    .linkPanel > a {
-      padding-left: 3px;
-      padding-right: 3px;
-      text-decoration: none;
-      vertical-align: middle;
-      display: inline-block;
-    }
-
-    .selected {
-      font-weight: bold;
-      background-color: selectionColor;
-    }
-
-    .hidden {
-      visibility: hidden;
-    }
-  </ui:style>
-
-  <g:HTMLPanel>
-    <g:HTMLPanel styleName='{style.linkPanel}' ui:field='linkPanel'/>
-  </g:HTMLPanel>
-</ui:UiBinder>
-
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchTable.java
deleted file mode 100644
index 4f2466f..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchTable.java
+++ /dev/null
@@ -1,901 +0,0 @@
-// Copyright (C) 2008 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.client.patches;
-
-import com.google.gerrit.client.Dispatcher;
-import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.client.changes.Util;
-import com.google.gerrit.client.ui.InlineHyperlink;
-import com.google.gerrit.client.ui.ListenableAccountDiffPreference;
-import com.google.gerrit.client.ui.NavigationTable;
-import com.google.gerrit.client.ui.PatchLink;
-import com.google.gerrit.common.data.PatchSetDetail;
-import com.google.gerrit.extensions.client.GeneralPreferencesInfo.DiffView;
-import com.google.gerrit.reviewdb.client.Patch;
-import com.google.gerrit.reviewdb.client.Patch.ChangeType;
-import com.google.gerrit.reviewdb.client.Patch.PatchType;
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gwt.core.client.Scheduler;
-import com.google.gwt.core.client.Scheduler.RepeatingCommand;
-import com.google.gwt.event.dom.client.ClickEvent;
-import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.event.dom.client.KeyCodes;
-import com.google.gwt.event.dom.client.KeyPressEvent;
-import com.google.gwt.user.client.Command;
-import com.google.gwt.user.client.Window;
-import com.google.gwt.user.client.ui.Anchor;
-import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.FlowPanel;
-import com.google.gwt.user.client.ui.HTMLTable.Cell;
-import com.google.gwt.user.client.ui.Image;
-import com.google.gwt.user.client.ui.Label;
-import com.google.gwt.user.client.ui.Widget;
-import com.google.gwtexpui.globalkey.client.KeyCommand;
-import com.google.gwtexpui.progress.client.ProgressBar;
-import com.google.gwtexpui.safehtml.client.SafeHtml;
-import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-class PatchTable extends Composite {
-  interface PatchValidator {
-    /**
-     * @param patch
-     * @return true if patch is valid.
-     */
-    boolean isValid(Patch patch);
-  }
-
-  final PatchValidator PREFERENCE_VALIDATOR =
-      new PatchValidator() {
-        @Override
-        public boolean isValid(Patch patch) {
-          return !((listenablePrefs.get().skipDeleted
-              && patch.getChangeType().equals(ChangeType.DELETED))
-              || (listenablePrefs.get().skipUncommented
-              && patch.getCommentCount() == 0));
-        }
-
-      };
-
-  private final FlowPanel myBody;
-  private PatchSetDetail detail;
-  private Command onLoadCommand;
-  private MyTable myTable;
-  private String savePointerId;
-  private PatchSet.Id base;
-  private List<Patch> patchList;
-  private Map<Patch.Key, Integer> patchMap;
-  private ListenableAccountDiffPreference listenablePrefs;
-
-  private List<ClickHandler> clickHandlers;
-  private boolean active;
-  private boolean registerKeys;
-
-  PatchTable(ListenableAccountDiffPreference prefs) {
-    listenablePrefs = prefs;
-    myBody = new FlowPanel();
-    initWidget(myBody);
-  }
-
-  PatchTable() {
-    this(new ListenableAccountDiffPreference());
-  }
-
-  int indexOf(Patch.Key patch) {
-    Integer i = patchMap().get(patch);
-    return i != null ? i : -1;
-  }
-
-  int size() {
-    return patchMap.size();
-  }
-
-  private Map<Patch.Key, Integer> patchMap() {
-    if (patchMap == null) {
-      patchMap = new HashMap<>();
-      for (int i = 0; i < patchList.size(); i++) {
-        patchMap.put(patchList.get(i).getKey(), i);
-      }
-    }
-    return patchMap;
-  }
-
-  void display(PatchSet.Id base, PatchSetDetail detail) {
-    this.base = base;
-    this.detail = detail;
-    this.patchList = detail.getPatches();
-    this.patchMap = null;
-    myTable = null;
-
-    final DisplayCommand cmd = new DisplayCommand(patchList, base);
-    if (cmd.execute()) {
-      cmd.initMeter();
-      Scheduler.get().scheduleIncremental(cmd);
-    } else {
-      cmd.showTable();
-    }
-  }
-
-  PatchSet.Id getBase() {
-    return base;
-  }
-
-  void setSavePointerId(final String id) {
-    savePointerId = id;
-  }
-
-  boolean isLoaded() {
-    return myTable != null;
-  }
-
-  void onTableLoaded(final Command cmd) {
-    if (myTable != null) {
-      cmd.execute();
-    } else {
-      onLoadCommand = cmd;
-    }
-  }
-
-  void addClickHandler(final ClickHandler clickHandler) {
-    if (myTable != null) {
-      myTable.addClickHandler(clickHandler);
-    } else {
-      if (clickHandlers == null) {
-        clickHandlers = new ArrayList<>(2);
-      }
-      clickHandlers.add(clickHandler);
-    }
-  }
-
-  void setRegisterKeys(final boolean on) {
-    registerKeys = on;
-    if (myTable != null) {
-      myTable.setRegisterKeys(on);
-    }
-  }
-
-  void movePointerTo(final Patch.Key k) {
-    if (myTable != null) {
-      myTable.movePointerTo(k);
-    }
-  }
-
-  void setActive(boolean active) {
-    this.active = active;
-    if (myTable != null) {
-      myTable.setActive(active);
-    }
-  }
-
-  void notifyDraftDelta(final Patch.Key k, final int delta) {
-    if (myTable != null) {
-      myTable.notifyDraftDelta(k, delta);
-    }
-  }
-
-  private void setMyTable(MyTable table) {
-    myBody.clear();
-    myBody.add(table);
-    myTable = table;
-
-    if (clickHandlers != null) {
-      for (ClickHandler ch : clickHandlers) {
-        myTable.addClickHandler(ch);
-      }
-      clickHandlers = null;
-    }
-
-    if (active) {
-      myTable.setActive(true);
-      active = false;
-    }
-
-    if (registerKeys) {
-      myTable.setRegisterKeys(registerKeys);
-      registerKeys = false;
-    }
-
-    myTable.finishDisplay();
-  }
-
-  /**
-   * @return a link to the previous file in this patch set, or null.
-   */
-  InlineHyperlink getPreviousPatchLink(int index) {
-    int previousPatchIndex = getPreviousPatch(index, PREFERENCE_VALIDATOR);
-    if (previousPatchIndex < 0) {
-      return null;
-    }
-    return createLink(previousPatchIndex,
-        SafeHtml.asis(Util.C.prevPatchLinkIcon()), null);
-  }
-
-  /**
-   * @return a link to the next file in this patch set, or null.
-   */
-  InlineHyperlink getNextPatchLink(int index) {
-    int nextPatchIndex = getNextPatch(index, false, PREFERENCE_VALIDATOR);
-    if (nextPatchIndex < 0) {
-      return null;
-    }
-    return createLink(nextPatchIndex, null,
-        SafeHtml.asis(Util.C.nextPatchLinkIcon()));
-  }
-
-  /**
-   * @return a link to the the given patch.
-   * @param index The patch to link to
-   * @param before A string to display at the beginning of the href text
-   * @param after A string to display at the end of the href text
-   */
-  PatchLink createLink(int index, SafeHtml before, SafeHtml after) {
-    Patch patch = patchList.get(index);
-    Patch.Key thisKey = patch.getKey();
-    PatchLink link;
-
-    if (isUnifiedPatchLink(patch)) {
-      link = new PatchLink.Unified("", base, thisKey);
-    } else {
-      link = new PatchLink.SideBySide("", base, thisKey);
-    }
-
-    SafeHtmlBuilder text = new SafeHtmlBuilder();
-    text.append(before);
-    text.append(getFileNameOnly(patch));
-    text.append(after);
-    SafeHtml.set(link, text);
-    return link;
-  }
-
-  private static boolean isUnifiedPatchLink(final Patch patch) {
-    return (patch.getPatchType().equals(PatchType.BINARY)
-        || (Gerrit.isSignedIn()
-            && Gerrit.getUserPreferences().diffView()
-                .equals(DiffView.UNIFIED_DIFF)));
-  }
-
-  private static String getFileNameOnly(Patch patch) {
-    // Note: use '/' here and not File.pathSeparator since git paths
-    // are always separated by /
-    //
-    String fileName = getDisplayFileName(patch);
-    int s = fileName.lastIndexOf('/');
-    if (s >= 0) {
-      fileName = fileName.substring(s + 1);
-    }
-    return fileName;
-  }
-
-  static String getDisplayFileName(Patch patch) {
-    return getDisplayFileName(patch.getKey());
-  }
-
-  static String getDisplayFileName(Patch.Key patchKey) {
-    if (Patch.COMMIT_MSG.equals(patchKey.get())) {
-      return Util.C.commitMessage();
-    }
-    return patchKey.get();
-  }
-
-  /**
-   * Update the reviewed status for the given patch.
-   */
-  void updateReviewedStatus(Patch.Key patchKey, boolean reviewed) {
-    if (myTable != null) {
-      myTable.updateReviewedStatus(patchKey, reviewed);
-    }
-  }
-
-  ListenableAccountDiffPreference getPreferences() {
-    return listenablePrefs;
-  }
-
-  private class MyTable extends NavigationTable<Patch> {
-    private static final int C_PATH = 2;
-    private static final int C_DRAFT = 3;
-    private static final int C_SIZE = 4;
-    private static final int C_SIDEBYSIDE = 5;
-    private int activeRow = -1;
-
-    MyTable() {
-      keysNavigation.add(new PrevKeyCommand(0, 'k', Util.C.patchTablePrev()));
-      keysNavigation.add(new NextKeyCommand(0, 'j', Util.C.patchTableNext()));
-      keysNavigation.add(new OpenKeyCommand(0, 'o', Util.C.patchTableOpenDiff()));
-      keysNavigation.add(new OpenKeyCommand(0, KeyCodes.KEY_ENTER, Util.C
-          .patchTableOpenDiff()));
-      keysNavigation.add(new OpenUnifiedDiffKeyCommand(0, 'O', Util.C
-          .patchTableOpenUnifiedDiff()));
-
-      table.addClickHandler(new ClickHandler() {
-        @Override
-        public void onClick(final ClickEvent event) {
-          final Cell cell = table.getCellForEvent(event);
-          if (cell != null && cell.getRowIndex() > 0) {
-            movePointerTo(cell.getRowIndex());
-          }
-        }
-      });
-      setSavePointerId(PatchTable.this.savePointerId);
-    }
-
-    public void addClickHandler(final ClickHandler clickHandler) {
-      table.addClickHandler(clickHandler);
-    }
-
-    void updateReviewedStatus(final Patch.Key patchKey, boolean reviewed) {
-      int idx = patchMap().get(patchKey);
-      if (0 <= idx) {
-        Patch patch = patchList.get(idx);
-        if (patch.isReviewedByCurrentUser() != reviewed) {
-          int row = idx + 1;
-          int col = C_SIDEBYSIDE + 2;
-          if (patch.getPatchType() == Patch.PatchType.BINARY) {
-            col = C_SIDEBYSIDE + 3;
-          }
-          if (reviewed) {
-            table.setWidget(row, col, new Image(Gerrit.RESOURCES.greenCheck()));
-          } else {
-            table.clearCell(row, col);
-          }
-          patch.setReviewedByCurrentUser(reviewed);
-        }
-      }
-    }
-
-    void notifyDraftDelta(final Patch.Key key, final int delta) {
-      int idx = patchMap().get(key);
-      if (0 <= idx) {
-        Patch p = patchList.get(idx);
-        p.setDraftCount(p.getDraftCount() + delta);
-        SafeHtmlBuilder m = new SafeHtmlBuilder();
-        appendCommentCount(m, p);
-        SafeHtml.set(table, idx + 1, C_DRAFT, m);
-      }
-    }
-
-    @Override
-    public void resetHtml(final SafeHtml html) {
-      super.resetHtml(html);
-    }
-
-    @Override
-    public void movePointerTo(Object oldId) {
-      super.movePointerTo(oldId);
-    }
-
-    /** Activates / Deactivates the key navigation and the highlighting of the current row for this table */
-    void setActive(boolean active) {
-      if (active) {
-        if(activeRow > 0 && getCurrentRow() != activeRow) {
-          super.movePointerTo(activeRow);
-          activeRow = -1;
-        }
-      } else {
-        if(getCurrentRow() > 0) {
-          activeRow = getCurrentRow();
-          super.movePointerTo(-1);
-        }
-      }
-      setRegisterKeys(active);
-    }
-
-    void initializeRow(int row) {
-      Patch patch = PatchTable.this.patchList.get(row - 1);
-      setRowItem(row, patch);
-
-      Widget nameCol = new PatchLink.SideBySide(getDisplayFileName(patch), base,
-          patch.getKey());
-
-      if (patch.getSourceFileName() != null) {
-        final String text;
-        if (patch.getChangeType() == Patch.ChangeType.RENAMED) {
-          text = Util.M.renamedFrom(patch.getSourceFileName());
-        } else if (patch.getChangeType() == Patch.ChangeType.COPIED) {
-          text = Util.M.copiedFrom(patch.getSourceFileName());
-        } else {
-          text = Util.M.otherFrom(patch.getSourceFileName());
-        }
-        final Label line = new Label(text);
-        line.setStyleName(Gerrit.RESOURCES.css().sourceFilePath());
-        final FlowPanel cell = new FlowPanel();
-        cell.add(nameCol);
-        cell.add(line);
-        nameCol = cell;
-      }
-      table.setWidget(row, C_PATH, nameCol);
-
-      int C_UNIFIED = C_SIDEBYSIDE + 1;
-
-      PatchLink sideBySide = new PatchLink.SideBySide(
-          Util.C.patchTableDiffSideBySide(), base, patch.getKey());
-      sideBySide.setStyleName("gwt-Anchor");
-
-      PatchLink unified = new PatchLink.Unified(Util.C.patchTableDiffUnified(),
-          base, patch.getKey());
-      unified.setStyleName("gwt-Anchor");
-
-      table.setWidget(row, C_SIDEBYSIDE, sideBySide);
-      table.setWidget(row, C_UNIFIED, unified);
-    }
-
-    void initializeLastRow(int row) {
-      Anchor sideBySide = new Anchor(Util.C.diffAllSideBySide());
-      sideBySide.addClickHandler(new ClickHandler() {
-        @Override
-        public void onClick(ClickEvent event) {
-          for (Patch p : detail.getPatches()) {
-            openWindow(Dispatcher.toSideBySide(base, p.getKey()));
-          }
-        }
-      });
-      table.setWidget(row, C_SIDEBYSIDE - 2, sideBySide);
-
-      int C_UNIFIED = C_SIDEBYSIDE - 2 + 1;
-      Anchor unified = new Anchor(Util.C.diffAllUnified());
-      unified.addClickHandler(new ClickHandler() {
-        @Override
-        public void onClick(ClickEvent event) {
-          for (Patch p : detail.getPatches()) {
-            openWindow(Dispatcher.toUnified(base, p.getKey()));
-          }
-        }
-      });
-      table.setWidget(row, C_UNIFIED, unified);
-    }
-
-    private void openWindow(String token) {
-      String url = Window.Location.getPath() + "#" + token;
-      Window.open(url, "_blank", null);
-    }
-
-    void appendHeader(final SafeHtmlBuilder m) {
-      m.openTr();
-
-      // Cursor
-      m.openTd();
-      m.addStyleName(Gerrit.RESOURCES.css().iconHeader());
-      m.addStyleName(Gerrit.RESOURCES.css().leftMostCell());
-      m.nbsp();
-      m.closeTd();
-
-      // Mode
-      m.openTd();
-      m.setStyleName(Gerrit.RESOURCES.css().iconHeader());
-      m.nbsp();
-      m.closeTd();
-
-      // "File path"
-      m.openTd();
-      m.setStyleName(Gerrit.RESOURCES.css().dataHeader());
-      m.append(Util.C.patchTableColumnName());
-      m.closeTd();
-
-      // "Comments"
-      m.openTd();
-      m.setStyleName(Gerrit.RESOURCES.css().dataHeader());
-      m.append(Util.C.patchTableColumnComments());
-      m.closeTd();
-
-      // "Size"
-      m.openTd();
-      m.setStyleName(Gerrit.RESOURCES.css().dataHeader());
-      m.append(Util.C.patchTableColumnSize());
-      m.closeTd();
-
-      // "Diff"
-      m.openTd();
-      m.setStyleName(Gerrit.RESOURCES.css().dataHeader());
-      m.setAttribute("colspan", 3);
-      m.append(Util.C.patchTableColumnDiff());
-      m.closeTd();
-
-      // "Reviewed"
-      if (Gerrit.isSignedIn()) {
-        m.openTd();
-        m.setStyleName(Gerrit.RESOURCES.css().iconHeader());
-        m.addStyleName(Gerrit.RESOURCES.css().dataHeader());
-        m.append(Util.C.reviewed());
-        m.closeTd();
-      }
-
-      m.closeTr();
-    }
-
-    void appendRow(final SafeHtmlBuilder m, final Patch p,
-        final boolean isReverseDiff) {
-      m.openTr();
-
-      m.openTd();
-      m.addStyleName(Gerrit.RESOURCES.css().iconCell());
-      m.addStyleName(Gerrit.RESOURCES.css().leftMostCell());
-      m.nbsp();
-      m.closeTd();
-
-      m.openTd();
-      m.setStyleName(Gerrit.RESOURCES.css().changeTypeCell());
-      if (isReverseDiff) {
-        m.addStyleName(Gerrit.RESOURCES.css().patchCellReverseDiff());
-      }
-
-      if (Patch.COMMIT_MSG.equals(p.getFileName())) {
-        m.nbsp();
-      } else {
-        m.append(p.getChangeType().getCode());
-      }
-      m.closeTd();
-
-      m.openTd();
-      m.addStyleName(Gerrit.RESOURCES.css().dataCell());
-      m.addStyleName(Gerrit.RESOURCES.css().filePathCell());
-      m.closeTd();
-
-      m.openTd();
-      m.addStyleName(Gerrit.RESOURCES.css().dataCell());
-      m.addStyleName(Gerrit.RESOURCES.css().commentCell());
-      appendCommentCount(m, p);
-      m.closeTd();
-
-      m.openTd();
-      m.addStyleName(Gerrit.RESOURCES.css().dataCell());
-
-      m.addStyleName(Gerrit.RESOURCES.css().patchSizeCell());
-      if (isReverseDiff) {
-        m.addStyleName(Gerrit.RESOURCES.css().patchCellReverseDiff());
-      }
-
-      appendSize(m, p);
-      m.closeTd();
-
-      // Diff
-      openlink(m, 2);
-      m.closeTd();
-      openlink(m, 1);
-      m.closeTd();
-
-      // Green check mark if the user is logged in and they reviewed that file
-      if (Gerrit.isSignedIn()) {
-        m.openTd();
-        m.setStyleName(Gerrit.RESOURCES.css().dataCell());
-        if (p.isReviewedByCurrentUser()) {
-          m.openDiv();
-          m.setStyleName(Gerrit.RESOURCES.css().greenCheckClass());
-          m.closeSelf();
-        }
-        m.closeTd();
-      }
-
-      m.closeTr();
-    }
-
-    void appendLastRow(final SafeHtmlBuilder m, int ins, int dels,
-        final boolean isReverseDiff) {
-      m.openTr();
-
-      m.openTd();
-      m.addStyleName(Gerrit.RESOURCES.css().iconCell());
-      m.addStyleName(Gerrit.RESOURCES.css().noborder());
-      m.nbsp();
-      m.closeTd();
-
-      m.openTd();
-      m.setAttribute("colspan", C_SIZE - 1);
-      m.closeTd();
-
-      m.openTd();
-      m.addStyleName(Gerrit.RESOURCES.css().dataCell());
-      m.addStyleName(Gerrit.RESOURCES.css().patchSizeCell());
-      m.addStyleName(Gerrit.RESOURCES.css().leftMostCell());
-
-      if (isReverseDiff) {
-        m.addStyleName(Gerrit.RESOURCES.css().patchCellReverseDiff());
-      }
-
-      m.append(Util.M.patchTableSize_Modify(ins, dels));
-      m.closeTd();
-
-      openlink(m, 2);
-      m.closeTd();
-
-      openlink(m, 1);
-      m.closeTd();
-
-      m.closeTr();
-    }
-
-    void appendCommentCount(final SafeHtmlBuilder m, final Patch p) {
-      if (p.getCommentCount() > 0) {
-        m.append(Util.M.patchTableComments(p.getCommentCount()));
-      }
-      if (p.getDraftCount() > 0) {
-        if (p.getCommentCount() > 0) {
-          m.append(", ");
-        }
-        m.openSpan();
-        m.setStyleName(Gerrit.RESOURCES.css().drafts());
-        m.append(Util.M.patchTableDrafts(p.getDraftCount()));
-        m.closeSpan();
-      }
-    }
-
-    void appendSize(final SafeHtmlBuilder m, final Patch p) {
-      if (Patch.COMMIT_MSG.equals(p.getFileName())) {
-        m.nbsp();
-        return;
-      }
-
-      if (p.getPatchType() == PatchType.UNIFIED) {
-        int ins = p.getInsertions();
-        int dels = p.getDeletions();
-
-        switch (p.getChangeType()) {
-          case ADDED:
-            m.append(Util.M.patchTableSize_Lines(ins));
-            break;
-
-          case DELETED:
-            m.nbsp();
-            break;
-
-          case MODIFIED:
-          case COPIED:
-          case RENAMED:
-            m.append(Util.M.patchTableSize_Modify(ins, dels));
-            break;
-
-          case REWRITE:
-            break;
-        }
-      } else {
-        m.nbsp();
-      }
-    }
-
-    private void openlink(final SafeHtmlBuilder m, final int colspan) {
-      m.openTd();
-      m.addStyleName(Gerrit.RESOURCES.css().dataCell());
-      m.addStyleName(Gerrit.RESOURCES.css().diffLinkCell());
-      m.setAttribute("colspan", colspan);
-    }
-
-    @Override
-    protected Object getRowItemKey(final Patch item) {
-      return item.getKey();
-    }
-
-    @Override
-    protected void onOpenRow(final int row) {
-      Widget link = table.getWidget(row, C_PATH);
-      if (link instanceof FlowPanel) {
-        link = ((FlowPanel) link).getWidget(0);
-      }
-      if (link instanceof InlineHyperlink) {
-        ((InlineHyperlink) link).go();
-      }
-    }
-
-    private final class OpenUnifiedDiffKeyCommand extends KeyCommand {
-
-      public OpenUnifiedDiffKeyCommand(int mask, char key, String help) {
-        super(mask, key, help);
-      }
-
-      @Override
-      public void onKeyPress(KeyPressEvent event) {
-        Widget link = table.getWidget(getCurrentRow(), C_PATH);
-        if (link instanceof FlowPanel) {
-          link = ((FlowPanel) link).getWidget(0);
-        }
-        if (link instanceof PatchLink.Unified) {
-          ((InlineHyperlink) link).go();
-        } else {
-          link = table.getWidget(getCurrentRow(), C_SIDEBYSIDE + 1);
-          if (link instanceof PatchLink.Unified) {
-            ((InlineHyperlink) link).go();
-          }
-        }
-      }
-    }
-  }
-
-  private final class DisplayCommand implements RepeatingCommand {
-    private final MyTable table;
-    private final List<Patch> list;
-    private boolean attached;
-    private SafeHtmlBuilder nc = new SafeHtmlBuilder();
-    private int stage = 0;
-    private int row;
-    private double start;
-    private ProgressBar meter;
-
-    private int insertions;
-    private int deletions;
-
-    private final PatchSet.Id psIdToCompareWith;
-
-    private DisplayCommand(final List<Patch> list, final PatchSet.Id psIdToCompareWith) {
-      this.table = new MyTable();
-      this.list = list;
-      this.psIdToCompareWith = psIdToCompareWith;
-    }
-
-    /**
-     * Add the files contained in the list of patches to the table, one per row.
-     */
-    @Override
-    @SuppressWarnings("fallthrough")
-    public boolean execute() {
-      final boolean attachedNow = isAttached();
-      if (!attached && attachedNow) {
-        // Remember that we have been attached at least once. If
-        // later we find we aren't attached we should stop running.
-        //
-        attached = true;
-      } else if (attached && !attachedNow) {
-        // If the user navigated away, we aren't in the DOM anymore.
-        // Don't continue to render.
-        //
-        return false;
-      }
-
-      boolean isReverseDiff = false;
-
-      if (psIdToCompareWith != null
-          && list.get(0).getKey().getParentKey().get() < psIdToCompareWith.get()) {
-        isReverseDiff = true;
-      }
-
-      start = System.currentTimeMillis();
-      switch (stage) {
-        case 0:
-          if (row == 0) {
-            table.appendHeader(nc);
-            table.appendRow(nc, list.get(row++), isReverseDiff);
-          }
-          while (row < list.size()) {
-            Patch p = list.get(row);
-            insertions += p.getInsertions();
-            deletions += p.getDeletions();
-            table.appendRow(nc, p, isReverseDiff);
-            if ((++row % 10) == 0 && longRunning()) {
-              updateMeter();
-              return true;
-            }
-          }
-          table.appendLastRow(nc, insertions, deletions, isReverseDiff);
-          table.resetHtml(nc);
-          table.initializeLastRow(row + 1);
-          nc = null;
-          stage = 1;
-          row = 0;
-
-        case 1:
-          while (row < list.size()) {
-            table.initializeRow(row + 1);
-            if ((++row % 50) == 0 && longRunning()) {
-              updateMeter();
-              return true;
-            }
-          }
-          updateMeter();
-          showTable();
-      }
-      return false;
-    }
-
-    void showTable() {
-      setMyTable(table);
-
-      if (PatchTable.this.onLoadCommand != null) {
-        PatchTable.this.onLoadCommand.execute();
-        PatchTable.this.onLoadCommand = null;
-      }
-    }
-
-    void initMeter() {
-      if (meter == null) {
-        meter = new ProgressBar(Util.M.loadingPatchSet(detail.getPatchSet().getId().get()));
-        PatchTable.this.myBody.clear();
-        PatchTable.this.myBody.add(meter);
-      }
-      updateMeter();
-    }
-
-    void updateMeter() {
-      if (meter != null) {
-        final int n = list.size();
-        meter.setValue(((100 * (stage * n + row)) / (2 * n)));
-      }
-    }
-
-    private boolean longRunning() {
-      return System.currentTimeMillis() - start > 200;
-    }
-  }
-
-
-  /**
-   * Gets the next patch
-   *
-   * @param currentIndex
-   * @param validators
-   * @param loopAround loops back around to the front and traverses if this is
-   *        true
-   * @return index of next valid patch, or -1 if no valid patches
-   */
-  int getNextPatch(int currentIndex, boolean loopAround,
-      PatchValidator... validators) {
-    return getNextPatchHelper(currentIndex, loopAround, detail.getPatches()
-        .size(), validators);
-  }
-
-  /**
-   * Helper function for getNextPatch
-   *
-   * @param currentIndex
-   * @param validators
-   * @param loopAround
-   * @param maxIndex will only traverse up to this index
-   * @return index of next valid patch, or -1 if no valid patches
-   */
-  private int getNextPatchHelper(int currentIndex, boolean loopAround,
-      int maxIndex, PatchValidator... validators) {
-    for (int i = currentIndex + 1; i < maxIndex; i++) {
-      Patch patch = detail.getPatches().get(i);
-      if (patch != null && patchIsValid(patch, validators)) {
-        return i;
-      }
-    }
-
-    if (loopAround) {
-      return getNextPatchHelper(-1, false, currentIndex, validators);
-    }
-
-    return -1;
-  }
-
-  /**
-   * @return the index to the previous patch
-   */
-  int getPreviousPatch(int currentIndex, PatchValidator... validators) {
-    for (int i = currentIndex - 1; i >= 0; i--) {
-      Patch patch = detail.getPatches().get(i);
-      if (patch != null && patchIsValid(patch, validators)) {
-        return i;
-      }
-    }
-
-    return -1;
-  }
-
-  /**
-   * Helper function that returns whether a patch is valid or not
-   *
-   * @param patch
-   * @param validators
-   * @return whether the patch is valid based on the validators
-   */
-  private boolean patchIsValid(Patch patch, PatchValidator... validators) {
-    for (PatchValidator v : validators) {
-      if (!v.isValid(patch)) {
-        return false;
-      }
-    }
-    return true;
-  }
-}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchUtil.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchUtil.java
index e949194..d599756 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchUtil.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchUtil.java
@@ -14,22 +14,9 @@
 
 package com.google.gerrit.client.patches;
 
-import com.google.gerrit.common.data.ChangeDetailService;
-import com.google.gerrit.common.data.PatchDetailService;
 import com.google.gwt.core.client.GWT;
-import com.google.gwtjsonrpc.client.JsonUtil;
 
 public class PatchUtil {
   public static final PatchConstants C = GWT.create(PatchConstants.class);
   public static final PatchMessages M = GWT.create(PatchMessages.class);
-  public static final ChangeDetailService CHANGE_SVC;
-  public static final PatchDetailService PATCH_SVC;
-
-  static {
-    CHANGE_SVC = GWT.create(ChangeDetailService.class);
-    JsonUtil.bind(CHANGE_SVC, "rpc/ChangeDetailService");
-
-    PATCH_SVC = GWT.create(PatchDetailService.class);
-    JsonUtil.bind(PATCH_SVC, "rpc/PatchDetailService");
-  }
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/ReviewedPanels.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/ReviewedPanels.java
deleted file mode 100644
index d889c79..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/ReviewedPanels.java
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright (C) 2012 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.client.patches;
-
-import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.client.VoidResult;
-import com.google.gerrit.client.changes.Util;
-import com.google.gerrit.client.patches.PatchTable.PatchValidator;
-import com.google.gerrit.client.rpc.RestApi;
-import com.google.gerrit.client.ui.ChangeLink;
-import com.google.gerrit.client.ui.InlineHyperlink;
-import com.google.gerrit.reviewdb.client.Patch;
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gwt.event.dom.client.ClickEvent;
-import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.event.logical.shared.ValueChangeEvent;
-import com.google.gwt.event.logical.shared.ValueChangeHandler;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwt.user.client.ui.Anchor;
-import com.google.gwt.user.client.ui.CheckBox;
-import com.google.gwt.user.client.ui.FlowPanel;
-import com.google.gwtexpui.safehtml.client.SafeHtml;
-import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
-
-class ReviewedPanels {
-  final FlowPanel top;
-  final FlowPanel bottom;
-
-  private Patch.Key patchKey;
-  private PatchTable fileList;
-  private InlineHyperlink reviewedLink;
-  private CheckBox checkBoxTop;
-  private CheckBox checkBoxBottom;
-
-  ReviewedPanels() {
-    this.top = new FlowPanel();
-    this.bottom = new FlowPanel();
-    this.bottom.setStyleName(Gerrit.RESOURCES.css().reviewedPanelBottom());
-  }
-
-  void populate(Patch.Key pk, PatchTable pt, int patchIndex) {
-    patchKey = pk;
-    fileList = pt;
-    reviewedLink = createReviewedLink(patchIndex);
-
-    top.clear();
-    checkBoxTop = createReviewedCheckbox();
-    top.add(checkBoxTop);
-    top.add(createReviewedAnchor());
-
-    bottom.clear();
-    checkBoxBottom = createReviewedCheckbox();
-    bottom.add(checkBoxBottom);
-    bottom.add(createReviewedAnchor());
-  }
-
-  private CheckBox createReviewedCheckbox() {
-    final CheckBox checkBox = new CheckBox(PatchUtil.C.reviewedAnd() + " ");
-    checkBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
-      @Override
-      public void onValueChange(ValueChangeEvent<Boolean> event) {
-        final boolean value = event.getValue();
-        setReviewedByCurrentUser(value);
-        if (checkBoxTop.getValue() != value) {
-          checkBoxTop.setValue(value);
-        }
-        if (checkBoxBottom.getValue() != value) {
-          checkBoxBottom.setValue(value);
-        }
-      }
-    });
-    return checkBox;
-  }
-
-  boolean getValue() {
-    return checkBoxTop.getValue();
-  }
-
-  void setValue(final boolean value) {
-    checkBoxTop.setValue(value);
-    checkBoxBottom.setValue(value);
-  }
-
-  void setReviewedByCurrentUser(boolean reviewed) {
-    PatchSet.Id ps = patchKey.getParentKey();
-    if (ps.get() != 0) {
-      if (fileList != null) {
-        fileList.updateReviewedStatus(patchKey, reviewed);
-      }
-
-      RestApi api = new RestApi("/changes/").id(ps.getParentKey().get())
-          .view("revisions").id(ps.get())
-          .view("files").id(patchKey.getFileName())
-          .view("reviewed");
-
-      AsyncCallback<VoidResult> cb = new AsyncCallback<VoidResult>() {
-        @Override
-        public void onFailure(Throwable arg0) {
-          // nop
-        }
-
-        @Override
-        public void onSuccess(VoidResult result) {
-          // nop
-        }
-      };
-      if (reviewed) {
-        api.put(cb);
-      } else {
-        api.delete(cb);
-      }
-    }
-  }
-
-  void go() {
-    if (reviewedLink != null) {
-      setReviewedByCurrentUser(true);
-      reviewedLink.go();
-    }
-  }
-
-  private InlineHyperlink createReviewedLink(final int patchIndex) {
-    final PatchValidator unreviewedValidator = new PatchValidator() {
-      @Override
-      public boolean isValid(Patch patch) {
-        return !patch.isReviewedByCurrentUser();
-      }
-    };
-
-    InlineHyperlink reviewedLink = new ChangeLink("", patchKey.getParentKey());
-    if (fileList != null) {
-      int nextUnreviewedPatchIndex =
-          fileList.getNextPatch(patchIndex, true, unreviewedValidator,
-              fileList.PREFERENCE_VALIDATOR);
-
-      if (nextUnreviewedPatchIndex > -1) {
-        // Create invisible patch link to change page
-        reviewedLink =
-            fileList.createLink(nextUnreviewedPatchIndex, null, null);
-        reviewedLink.setText("");
-      }
-    }
-    return reviewedLink;
-  }
-
-  private Anchor createReviewedAnchor() {
-    SafeHtmlBuilder text = new SafeHtmlBuilder();
-    text.append(PatchUtil.C.next());
-    text.append(SafeHtml.asis(Util.C.nextPatchLinkIcon()));
-
-    Anchor reviewedAnchor = new Anchor("");
-    SafeHtml.set(reviewedAnchor, text);
-
-    reviewedAnchor.addClickHandler(new ClickHandler() {
-      @Override
-      public void onClick(ClickEvent event) {
-        setReviewedByCurrentUser(true);
-        reviewedLink.go();
-      }
-    });
-
-    return reviewedAnchor;
-  }
-}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedDiffTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedDiffTable.java
deleted file mode 100644
index 156545a..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedDiffTable.java
+++ /dev/null
@@ -1,643 +0,0 @@
-// Copyright (C) 2008 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.client.patches;
-
-import static com.google.gerrit.client.patches.PatchLine.Type.CONTEXT;
-import static com.google.gerrit.client.patches.PatchLine.Type.DELETE;
-import static com.google.gerrit.client.patches.PatchLine.Type.INSERT;
-
-import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.common.data.CommentDetail;
-import com.google.gerrit.common.data.PatchScript;
-import com.google.gerrit.common.data.PatchScript.DisplayMethod;
-import com.google.gerrit.common.data.PatchSetDetail;
-import com.google.gerrit.prettify.client.SparseHtmlFile;
-import com.google.gerrit.prettify.common.EditList;
-import com.google.gerrit.prettify.common.EditList.Hunk;
-import com.google.gerrit.reviewdb.client.PatchLineComment;
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gwt.dom.client.Element;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
-import com.google.gwt.user.client.ui.UIObject;
-import com.google.gwtexpui.safehtml.client.SafeHtml;
-import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.List;
-
-public class UnifiedDiffTable extends AbstractPatchContentTable {
-  private static final int PC = 3;
-  private static final Comparator<PatchLineComment> BY_DATE =
-      new Comparator<PatchLineComment>() {
-        @Override
-        public int compare(final PatchLineComment o1, final PatchLineComment o2) {
-          return o1.getWrittenOn().compareTo(o2.getWrittenOn());
-        }
-      };
-
-  protected boolean isFileCommentBorderRowExist;
-  // Cursors.
-  protected int rowOfTableHeaderB;
-  protected int borderRowOfFileComment;
-
-  @Override
-  protected void onCellDoubleClick(final int row, final int column) {
-    if (column > C_ARROW && getRowItem(row) instanceof PatchLine) {
-      final PatchLine pl = (PatchLine) getRowItem(row);
-      switch (pl.getType()) {
-        case DELETE:
-        case CONTEXT:
-          createCommentEditor(row + 1, PC, pl.getLineA(), (short) 0);
-          break;
-        case INSERT:
-          createCommentEditor(row + 1, PC, pl.getLineB(), (short) 1);
-          break;
-        case REPLACE:
-          break;
-      }
-    }
-  }
-
-  @Override
-  protected void updateCursor(final PatchLineComment newComment) {
-    if (newComment.getLine() == R_HEAD) {
-      final PatchSet.Id psId =
-          newComment.getKey().getParentKey().getParentKey();
-      switch (newComment.getSide()) {
-        case FILE_SIDE_A:
-          if (idSideA == null && idSideB.equals(psId)) {
-            rowOfTableHeaderB++;
-            borderRowOfFileComment++;
-            return;
-          }
-          break;
-        case FILE_SIDE_B:
-          if (idSideA != null && idSideA.equals(psId)) {
-            rowOfTableHeaderB++;
-            borderRowOfFileComment++;
-          } else if (idSideB.equals(psId)) {
-            borderRowOfFileComment++;
-          }
-      }
-    }
-  }
-
-  @Override
-  protected void onCellSingleClick(Event event, int row, int column) {
-    super.onCellSingleClick(event, row, column);
-    if (column == 1 || column == 2) {
-      if (!"".equals(table.getText(row, column))) {
-        onCellDoubleClick(row, column);
-      }
-    }
-  }
-
-  @Override
-  protected void destroyCommentRow(final int row) {
-    super.destroyCommentRow(row);
-    if (this.rowOfTableHeaderB + 1 == row && row + 1 == borderRowOfFileComment) {
-      table.removeRow(row);
-      isFileCommentBorderRowExist = false;
-    }
-  }
-
-  @Override
-  public void remove(CommentEditorPanel panel) {
-    super.remove(panel);
-    if (panel.getComment().getLine() == AbstractPatchContentTable.R_HEAD) {
-      final PatchSet.Id psId =
-          panel.getComment().getKey().getParentKey().getParentKey();
-      switch (panel.getComment().getSide()) {
-        case FILE_SIDE_A:
-          if (idSideA == null && idSideB.equals(psId)) {
-            rowOfTableHeaderB--;
-            borderRowOfFileComment--;
-            return;
-          }
-          break;
-        case FILE_SIDE_B:
-          if (idSideA != null && idSideA.equals(psId)) {
-            rowOfTableHeaderB--;
-            borderRowOfFileComment--;
-          } else if (idSideB.equals(psId)) {
-            borderRowOfFileComment--;
-          }
-      }
-    }
-  }
-
-  @Override
-  protected void onInsertComment(final PatchLine pl) {
-    final int row = getCurrentRow();
-    switch (pl.getType()) {
-      case DELETE:
-      case CONTEXT:
-        createCommentEditor(row + 1, PC, pl.getLineA(), (short) 0);
-        break;
-      case INSERT:
-        createCommentEditor(row + 1, PC, pl.getLineB(), (short) 1);
-        break;
-      case REPLACE:
-        break;
-    }
-  }
-
-  private void appendImgTag(SafeHtmlBuilder nc, String url) {
-    nc.openElement("img");
-    nc.setAttribute("src", url);
-    nc.closeElement("img");
-  }
-
-  @Override
-  protected void createFileCommentEditorOnSideA() {
-    createCommentEditor(R_HEAD + 1, PC, R_HEAD, FILE_SIDE_A);
-  }
-
-  @Override
-  protected void createFileCommentEditorOnSideB() {
-    createCommentEditor(rowOfTableHeaderB + 1, PC, R_HEAD, FILE_SIDE_B);
-    createFileCommentBorderRow();
-  }
-
-  private void populateTableHeader(final PatchScript script,
-      final PatchSetDetail detail) {
-    initHeaders(script, detail);
-    table.setWidget(R_HEAD, PC, headerSideA);
-    table.setWidget(rowOfTableHeaderB, PC, headerSideB);
-    table.getFlexCellFormatter().addStyleName(R_HEAD, PC,
-        Gerrit.RESOURCES.css().unifiedTableHeader());
-    table.getFlexCellFormatter().addStyleName(rowOfTableHeaderB, PC,
-        Gerrit.RESOURCES.css().unifiedTableHeader());
-
-    // Add icons to lineNumber column header
-    if (headerSideA.isFileOrCommitMessage()) {
-      table.setWidget(R_HEAD, 1, iconA);
-    }
-    if (headerSideB.isFileOrCommitMessage()) {
-      table.setWidget(rowOfTableHeaderB, 2, iconB);
-    }
-  }
-
-  private void allocateTableHeader(SafeHtmlBuilder nc) {
-    rowOfTableHeaderB = 1;
-    borderRowOfFileComment = 2;
-    for (int i = R_HEAD; i < borderRowOfFileComment; i++) {
-      openTableHeaderLine(nc);
-      padLineNumberOnTableHeaderForSideA(nc);
-      padLineNumberOnTableHeaderForSideB(nc);
-      nc.openTd();
-      nc.setStyleName(Gerrit.RESOURCES.css().fileLine());
-      nc.addStyleName(Gerrit.RESOURCES.css().fileColumnHeader());
-      nc.closeTd();
-      closeLine(nc);
-    }
-  }
-
-  @Override
-  protected void render(final PatchScript script, final PatchSetDetail detail) {
-    final SafeHtmlBuilder nc = new SafeHtmlBuilder();
-    allocateTableHeader(nc);
-
-    // Display the patch header
-    for (final String line : script.getPatchHeader()) {
-      appendFileHeader(nc, line);
-    }
-    final ArrayList<PatchLine> lines = new ArrayList<>();
-
-    if (hasDifferences(script)) {
-      if (script.getDisplayMethodA() == DisplayMethod.IMG
-          || script.getDisplayMethodB() == DisplayMethod.IMG) {
-        appendImageDifferences(script, nc);
-      } else if (!isDisplayBinary) {
-        appendTextDifferences(script, nc, lines);
-      }
-    } else {
-      appendNoDifferences(nc);
-    }
-
-    resetHtml(nc);
-    populateTableHeader(script, detail);
-    if (hasDifferences(script)) {
-      initScript(script);
-      if (!isDisplayBinary) {
-        int row = script.getPatchHeader().size();
-        final CellFormatter fmt = table.getCellFormatter();
-        final Iterator<PatchLine> iLine = lines.iterator();
-        while (iLine.hasNext()) {
-          final PatchLine l = iLine.next();
-          final String n;
-          switch (l.getType()) {
-            case CONTEXT:
-              n = Gerrit.RESOURCES.css().diffTextCONTEXT();
-              break;
-            case DELETE:
-              n = Gerrit.RESOURCES.css().diffTextDELETE();
-              break;
-            case INSERT:
-              n = Gerrit.RESOURCES.css().diffTextINSERT();
-              break;
-            case REPLACE:
-            default:
-              continue;
-          }
-          while (!fmt.getStyleName(row, PC).contains(n)) {
-            row++;
-          }
-          setRowItem(row++, l);
-        }
-      }
-    }
-  }
-
-  private void appendImageLine(final SafeHtmlBuilder nc, final String url,
-      final boolean syntaxHighlighting, final boolean isInsert) {
-    nc.openTr();
-    nc.setAttribute("valign", "center");
-    nc.setAttribute("align", "center");
-
-    nc.openTd();
-    nc.setStyleName(Gerrit.RESOURCES.css().iconCell());
-    nc.closeTd();
-
-    padLineNumberForSideA(nc);
-    padLineNumberForSideB(nc);
-
-    nc.openTd();
-    nc.setStyleName(Gerrit.RESOURCES.css().fileLine());
-    if (isInsert) {
-      setStyleInsert(nc, syntaxHighlighting);
-    } else {
-      setStyleDelete(nc, syntaxHighlighting);
-    }
-    appendImgTag(nc, url);
-    nc.closeTd();
-
-    nc.closeTr();
-  }
-
-  private void appendImageDifferences(final PatchScript script,
-      final SafeHtmlBuilder nc) {
-    final boolean syntaxHighlighting =
-        script.getDiffPrefs().syntaxHighlighting;
-    if (script.getDisplayMethodA() == DisplayMethod.IMG) {
-      final String url = getUrlA();
-      appendImageLine(nc, url, syntaxHighlighting, false);
-    }
-    if (script.getDisplayMethodB() == DisplayMethod.IMG) {
-      final String url = getUrlB();
-      appendImageLine(nc, url, syntaxHighlighting, true);
-    }
-  }
-
-  private void appendTextDifferences(final PatchScript script,
-      final SafeHtmlBuilder nc, final ArrayList<PatchLine> lines) {
-    final SparseHtmlFile a = getSparseHtmlFileA(script);
-    final SparseHtmlFile b = getSparseHtmlFileB(script);
-    final boolean syntaxHighlighting =
-        script.getDiffPrefs().syntaxHighlighting;
-    for (final EditList.Hunk hunk : script.getHunks()) {
-      appendHunkHeader(nc, hunk);
-      while (hunk.next()) {
-        if (hunk.isContextLine()) {
-          openLine(nc);
-          appendLineNumberForSideA(nc, hunk.getCurA());
-          appendLineNumberForSideB(nc, hunk.getCurB());
-          appendLineText(nc, false, CONTEXT, a, hunk.getCurA());
-          closeLine(nc);
-          hunk.incBoth();
-          lines.add(new PatchLine(CONTEXT, hunk.getCurA(), hunk.getCurB()));
-
-        } else if (hunk.isDeletedA()) {
-          openLine(nc);
-          appendLineNumberForSideA(nc, hunk.getCurA());
-          padLineNumberForSideB(nc);
-          appendLineText(nc, syntaxHighlighting, DELETE, a, hunk.getCurA());
-          closeLine(nc);
-          hunk.incA();
-          lines.add(new PatchLine(DELETE, hunk.getCurA(), -1));
-          if (a.size() == hunk.getCurA()
-              && script.getA().isMissingNewlineAtEnd()) {
-            appendNoLF(nc);
-          }
-
-        } else if (hunk.isInsertedB()) {
-          openLine(nc);
-          padLineNumberForSideA(nc);
-          appendLineNumberForSideB(nc, hunk.getCurB());
-          appendLineText(nc, syntaxHighlighting, INSERT, b, hunk.getCurB());
-          closeLine(nc);
-          hunk.incB();
-          lines.add(new PatchLine(INSERT, -1, hunk.getCurB()));
-          if (b.size() == hunk.getCurB()
-              && script.getB().isMissingNewlineAtEnd()) {
-            appendNoLF(nc);
-          }
-        }
-      }
-    }
-  }
-
-  @Override
-  public void display(final CommentDetail cd, boolean expandComments) {
-    if (cd == null || cd.isEmpty()) {
-      return;
-    }
-    setAccountInfoCache(cd.getAccounts());
-
-    final ArrayList<PatchLineComment> all = new ArrayList<>();
-    for (int row = 0; row < table.getRowCount();) {
-      final List<PatchLineComment> fora;
-      final List<PatchLineComment> forb;
-      if (row == R_HEAD) {
-        fora = cd.getForA(R_HEAD);
-        forb = cd.getForB(R_HEAD);
-        row++;
-
-        if (!fora.isEmpty()) {
-          row = insert(fora, row);
-        }
-        rowOfTableHeaderB = row;
-        borderRowOfFileComment = row + 1;
-        if (!forb.isEmpty()) {
-          row++;// Skip the Header of sideB.
-          row = insert(forb, row);
-          borderRowOfFileComment = row;
-          createFileCommentBorderRow();
-        }
-      } else if (getRowItem(row) instanceof PatchLine) {
-        final PatchLine pLine = (PatchLine) getRowItem(row);
-        fora = cd.getForA(pLine.getLineA());
-        forb = cd.getForB(pLine.getLineB());
-        row++;
-
-        if (!fora.isEmpty() && !forb.isEmpty()) {
-          all.clear();
-          all.addAll(fora);
-          all.addAll(forb);
-          Collections.sort(all, BY_DATE);
-          row = insert(all, row);
-
-        } else if (!fora.isEmpty()) {
-          row = insert(fora, row);
-
-        } else if (!forb.isEmpty()) {
-          row = insert(forb, row);
-        }
-      } else {
-        row++;
-        continue;
-      }
-    }
-  }
-
-  private void defaultStyle(final int row, final CellFormatter fmt) {
-    fmt.addStyleName(row, PC - 2, Gerrit.RESOURCES.css().lineNumber());
-    fmt.addStyleName(row, PC - 2, Gerrit.RESOURCES.css().rightBorder());
-    fmt.addStyleName(row, PC - 1, Gerrit.RESOURCES.css().lineNumber());
-    fmt.addStyleName(row, PC, Gerrit.RESOURCES.css().diffText());
-  }
-
-  @Override
-  protected void insertRow(final int row) {
-    super.insertRow(row);
-    final CellFormatter fmt = table.getCellFormatter();
-    defaultStyle(row, fmt);
-  }
-
-  private int insert(final List<PatchLineComment> in, int row) {
-    for (Iterator<PatchLineComment> ci = in.iterator(); ci.hasNext();) {
-      final PatchLineComment c = ci.next();
-      if (c.getLine() == R_HEAD) {
-        insertFileCommentRow(row);
-      } else {
-        insertRow(row);
-      }
-      bindComment(row, PC, c, !ci.hasNext());
-      row++;
-    }
-    return row;
-  }
-
-  @Override
-  protected void insertFileCommentRow(final int row) {
-    table.insertRow(row);
-    final CellFormatter fmt = table.getCellFormatter();
-
-    fmt.addStyleName(row, C_ARROW, //
-        Gerrit.RESOURCES.css().iconCellOfFileCommentRow());
-    defaultStyle(row, fmt);
-
-    fmt.addStyleName(row, C_ARROW, //
-        Gerrit.RESOURCES.css().cellsNextToFileComment());
-    fmt.addStyleName(row, PC - 2, //
-        Gerrit.RESOURCES.css().cellsNextToFileComment());
-    fmt.addStyleName(row, PC - 1, //
-        Gerrit.RESOURCES.css().cellsNextToFileComment());
-  }
-
-  private void createFileCommentBorderRow() {
-    if (!isFileCommentBorderRowExist) {
-      isFileCommentBorderRowExist = true;
-      table.insertRow(borderRowOfFileComment);
-      final CellFormatter fmt = table.getCellFormatter();
-      fmt.addStyleName(borderRowOfFileComment, C_ARROW, //
-          Gerrit.RESOURCES.css().iconCellOfFileCommentRow());
-      defaultStyle(borderRowOfFileComment, fmt);
-
-      final Element iconCell =
-          fmt.getElement(borderRowOfFileComment, C_ARROW);
-      UIObject.setStyleName(DOM.getParent(iconCell), //
-          Gerrit.RESOURCES.css().fileCommentBorder(), true);
-    }
-  }
-
-  private void appendFileHeader(final SafeHtmlBuilder m, final String line) {
-    openLine(m);
-    padLineNumberForSideA(m);
-    padLineNumberForSideB(m);
-
-    m.openTd();
-    m.setStyleName(Gerrit.RESOURCES.css().fileLine());
-    m.addStyleName(Gerrit.RESOURCES.css().diffText());
-    m.addStyleName(Gerrit.RESOURCES.css().diffTextFileHeader());
-    m.append(line);
-    m.closeTd();
-    closeLine(m);
-  }
-
-  private void appendHunkHeader(final SafeHtmlBuilder m, final Hunk hunk) {
-    openLine(m);
-    padLineNumberForSideA(m);
-    padLineNumberForSideB(m);
-
-    m.openTd();
-    m.setStyleName(Gerrit.RESOURCES.css().fileLine());
-    m.addStyleName(Gerrit.RESOURCES.css().diffText());
-    m.addStyleName(Gerrit.RESOURCES.css().diffTextHunkHeader());
-    m.append("@@ -");
-    appendRange(m, hunk.getCurA() + 1, hunk.getEndA() - hunk.getCurA());
-    m.append(" +");
-    appendRange(m, hunk.getCurB() + 1, hunk.getEndB() - hunk.getCurB());
-    m.append(" @@");
-    m.closeTd();
-
-    closeLine(m);
-  }
-
-  private void appendRange(final SafeHtmlBuilder m, final int begin,
-      final int cnt) {
-    switch (cnt) {
-      case 0:
-        m.append(begin - 1);
-        m.append(",0");
-        break;
-
-      case 1:
-        m.append(begin);
-        break;
-
-      default:
-        m.append(begin);
-        m.append(',');
-        m.append(cnt);
-        break;
-    }
-  }
-
-  private void setStyleDelete(final SafeHtmlBuilder m,
-      boolean syntaxHighlighting) {
-    m.addStyleName(Gerrit.RESOURCES.css().diffTextDELETE());
-    if (syntaxHighlighting) {
-      m.addStyleName(Gerrit.RESOURCES.css().fileLineDELETE());
-    }
-  }
-
-  private void setStyleInsert(final SafeHtmlBuilder m,
-      boolean syntaxHighlighting) {
-    m.addStyleName(Gerrit.RESOURCES.css().diffTextINSERT());
-    if (syntaxHighlighting) {
-      m.addStyleName(Gerrit.RESOURCES.css().fileLineINSERT());
-    }
-  }
-
-  private void appendLineText(final SafeHtmlBuilder m,
-      boolean syntaxHighlighting, final PatchLine.Type type,
-      final SparseHtmlFile src, final int i) {
-    final SafeHtml text = src.getSafeHtmlLine(i);
-    m.openTd();
-    m.setStyleName(Gerrit.RESOURCES.css().fileLine());
-    m.addStyleName(Gerrit.RESOURCES.css().diffText());
-    switch (type) {
-      case CONTEXT:
-        m.addStyleName(Gerrit.RESOURCES.css().diffTextCONTEXT());
-        m.nbsp();
-        m.append(text);
-        break;
-      case DELETE:
-        setStyleDelete(m, syntaxHighlighting);
-        m.append("-");
-        m.append(text);
-        break;
-      case INSERT:
-        setStyleInsert(m, syntaxHighlighting);
-        m.append("+");
-        m.append(text);
-        break;
-      case REPLACE:
-        break;
-    }
-    m.closeTd();
-  }
-
-  private void appendNoLF(final SafeHtmlBuilder m) {
-    openLine(m);
-    padLineNumberForSideA(m);
-    padLineNumberForSideB(m);
-    m.openTd();
-    m.addStyleName(Gerrit.RESOURCES.css().diffText());
-    m.addStyleName(Gerrit.RESOURCES.css().diffTextNoLF());
-    m.append("\\ No newline at end of file");
-    m.closeTd();
-    closeLine(m);
-  }
-
-  private void openLine(final SafeHtmlBuilder m) {
-    m.openTr();
-    m.setAttribute("valign", "top");
-    m.openTd();
-    m.setStyleName(Gerrit.RESOURCES.css().iconCell());
-    m.closeTd();
-  }
-
-  private void openTableHeaderLine(final SafeHtmlBuilder m) {
-    m.openTr();
-    m.openTd();
-    m.setStyleName(Gerrit.RESOURCES.css().iconCell());
-    m.addStyleName(Gerrit.RESOURCES.css().fileColumnHeader());
-    m.closeTd();
-  }
-
-  private void closeLine(final SafeHtmlBuilder m) {
-    m.closeTr();
-  }
-
-  private void padLineNumberForSideB(final SafeHtmlBuilder m) {
-    m.openTd();
-    m.setStyleName(Gerrit.RESOURCES.css().lineNumber());
-    m.closeTd();
-  }
-
-  private void padLineNumberForSideA(final SafeHtmlBuilder m) {
-    m.openTd();
-    m.setStyleName(Gerrit.RESOURCES.css().lineNumber());
-    m.addStyleName(Gerrit.RESOURCES.css().rightBorder());
-    m.closeTd();
-  }
-
-  private void appendLineNumberForSideB(final SafeHtmlBuilder m, final int idx) {
-    m.openTd();
-    m.setStyleName(Gerrit.RESOURCES.css().lineNumber());
-    m.append(SafeHtml.asis("<a href=\"javascript:void(0)\">"+ (idx + 1) + "</a>"));
-    m.closeTd();
-  }
-
-  private void appendLineNumberForSideA(final SafeHtmlBuilder m, final int idx) {
-    m.openTd();
-    m.setStyleName(Gerrit.RESOURCES.css().lineNumber());
-    m.addStyleName(Gerrit.RESOURCES.css().rightBorder());
-    m.append(SafeHtml.asis("<a href=\"javascript:void(0)\">"+ (idx + 1) + "</a>"));
-    m.closeTd();
-  }
-
-  private void padLineNumberOnTableHeaderForSideB(final SafeHtmlBuilder m) {
-    m.openTd();
-    m.setStyleName(Gerrit.RESOURCES.css().lineNumber());
-    m.addStyleName(Gerrit.RESOURCES.css().fileColumnHeader());
-    m.closeTd();
-  }
-
-  private void padLineNumberOnTableHeaderForSideA(final SafeHtmlBuilder m) {
-    m.openTd();
-    m.setStyleName(Gerrit.RESOURCES.css().lineNumber());
-    m.addStyleName(Gerrit.RESOURCES.css().fileColumnHeader());
-    m.addStyleName(Gerrit.RESOURCES.css().rightBorder());
-    m.closeTd();
-  }
-}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedPatchScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedPatchScreen.java
deleted file mode 100644
index e587aac..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedPatchScreen.java
+++ /dev/null
@@ -1,564 +0,0 @@
-// Copyright (C) 2008 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.client.patches;
-
-import com.google.gerrit.client.Dispatcher;
-import com.google.gerrit.client.ErrorDialog;
-import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.client.RpcStatus;
-import com.google.gerrit.client.diff.DiffApi;
-import com.google.gerrit.client.diff.DiffInfo;
-import com.google.gerrit.client.info.WebLinkInfo;
-import com.google.gerrit.client.projects.ConfigInfoCache;
-import com.google.gerrit.client.rpc.CallbackGroup;
-import com.google.gerrit.client.rpc.GerritCallback;
-import com.google.gerrit.client.rpc.ScreenLoadCallback;
-import com.google.gerrit.client.ui.CommentLinkProcessor;
-import com.google.gerrit.client.ui.InlineHyperlink;
-import com.google.gerrit.client.ui.ListenableAccountDiffPreference;
-import com.google.gerrit.client.ui.Screen;
-import com.google.gerrit.common.data.PatchScript;
-import com.google.gerrit.common.data.PatchSetDetail;
-import com.google.gerrit.extensions.client.DiffPreferencesInfo;
-import com.google.gerrit.prettify.client.ClientSideFormatter;
-import com.google.gerrit.prettify.client.PrettyFactory;
-import com.google.gerrit.reviewdb.client.Patch;
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gwt.core.client.Scheduler;
-import com.google.gwt.core.client.Scheduler.ScheduledCommand;
-import com.google.gwt.event.dom.client.KeyPressEvent;
-import com.google.gwt.event.logical.shared.ValueChangeEvent;
-import com.google.gwt.event.logical.shared.ValueChangeHandler;
-import com.google.gwt.event.shared.HandlerRegistration;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwt.user.client.ui.FlowPanel;
-import com.google.gwt.user.client.ui.ImageResourceRenderer;
-import com.google.gwtexpui.globalkey.client.GlobalKey;
-import com.google.gwtexpui.globalkey.client.KeyCommand;
-import com.google.gwtexpui.globalkey.client.KeyCommandSet;
-
-import java.util.Collections;
-import java.util.List;
-
-public class UnifiedPatchScreen extends Screen implements
-    CommentEditorContainer {
-  static final PrettyFactory PRETTY = ClientSideFormatter.FACTORY;
-  static final short LARGE_FILE_CONTEXT = 100;
-
-  /**
-   * What should be displayed in the top of the screen
-   */
-  public static enum TopView {
-    MAIN, COMMIT, PREFERENCES, PATCH_SETS, FILES
-  }
-
-  protected final Patch.Key patchKey;
-  protected PatchSetDetail patchSetDetail;
-  protected PatchTable fileList;
-  protected PatchSet.Id idSideA;
-  protected PatchSet.Id idSideB;
-  protected PatchScriptSettingsPanel settingsPanel;
-  protected TopView topView;
-  protected CommentLinkProcessor commentLinkProcessor;
-
-  private ReviewedPanels reviewedPanels;
-  private HistoryTable historyTable;
-  private FlowPanel topPanel;
-  private FlowPanel contentPanel;
-  private UnifiedDiffTable contentTable;
-  private CommitMessageBlock commitMessageBlock;
-  private NavLinks topNav;
-  private NavLinks bottomNav;
-
-  private int rpcSequence;
-  private PatchScript lastScript;
-
-  /** The index of the file we are currently looking at among the fileList */
-  private int patchIndex;
-  private ListenableAccountDiffPreference prefs;
-  private HandlerRegistration prefsHandler;
-
-  /** Keys that cause an action on this screen */
-  private KeyCommandSet keysNavigation;
-  private KeyCommandSet keysAction;
-  private HandlerRegistration regNavigation;
-  private HandlerRegistration regAction;
-  private boolean intralineFailure;
-  private boolean intralineTimeout;
-
-  public UnifiedPatchScreen(Patch.Key id, TopView top, PatchSet.Id baseId) {
-    patchKey = id;
-    topView = top;
-
-    idSideA = baseId; // null here means we're diff'ing from the Base
-    idSideB = id.getParentKey();
-
-    prefs = fileList != null
-        ? fileList.getPreferences()
-        : new ListenableAccountDiffPreference();
-    if (Gerrit.isSignedIn()) {
-      prefs.reset();
-    }
-    reviewedPanels = new ReviewedPanels();
-    settingsPanel = new PatchScriptSettingsPanel(prefs);
-  }
-
-  @Override
-  public void notifyDraftDelta(int delta) {
-    lastScript = null;
-  }
-
-  @Override
-  public void remove(CommentEditorPanel panel) {
-    lastScript = null;
-  }
-
-  private void update(DiffPreferencesInfo dp) {
-    // Did the user just turn on auto-review?
-    if (!reviewedPanels.getValue() && prefs.getOld().manualReview
-        && !dp.manualReview) {
-      reviewedPanels.setValue(true);
-      reviewedPanels.setReviewedByCurrentUser(true);
-    }
-
-    if (lastScript != null && canReuse(dp, lastScript)) {
-      lastScript.setDiffPrefs(dp);
-      RpcStatus.INSTANCE.onRpcStart(null);
-      settingsPanel.setEnabled(false);
-      Scheduler.get().scheduleDeferred(new ScheduledCommand() {
-        @Override
-        public void execute() {
-          try {
-            onResult(lastScript, false /* not the first time */);
-          } finally {
-            RpcStatus.INSTANCE.onRpcComplete(null);
-          }
-        }
-      });
-    } else {
-      refresh(false);
-    }
-  }
-
-  private boolean canReuse(DiffPreferencesInfo dp, PatchScript last) {
-    if (last.getDiffPrefs().ignoreWhitespace != dp.ignoreWhitespace) {
-      // Whitespace ignore setting requires server computation.
-      return false;
-    }
-
-    final int ctx = dp.context;
-    if (ctx == DiffPreferencesInfo.WHOLE_FILE_CONTEXT
-        && !last.getA().isWholeFile()) {
-      // We don't have the entire file here, so we can't render it.
-      return false;
-    }
-
-    if (last.getDiffPrefs().context < ctx && !last.getA().isWholeFile()) {
-      // We don't have sufficient context.
-      return false;
-    }
-
-    if (dp.syntaxHighlighting && !last.getA().isWholeFile()) {
-      // We need the whole file to syntax highlight accurately.
-      return false;
-    }
-
-    return true;
-  }
-
-  @Override
-  protected void onInitUI() {
-    super.onInitUI();
-
-    if (Gerrit.isSignedIn()) {
-      setTitleFarEast(reviewedPanels.top);
-    }
-
-    keysNavigation = new KeyCommandSet(Gerrit.C.sectionNavigation());
-    keysNavigation.add(new UpToChangeCommand(patchKey.getParentKey(), 0, 'u'));
-    keysNavigation.add(new FileListCmd(0, 'f', PatchUtil.C.fileList()));
-
-    if (Gerrit.isSignedIn()) {
-      keysAction = new KeyCommandSet(Gerrit.C.sectionActions());
-      keysAction
-          .add(new ToggleReviewedCmd(0, 'm', PatchUtil.C.toggleReviewed()));
-      keysAction.add(new MarkAsReviewedAndGoToNextCmd(0, 'M', PatchUtil.C
-          .markAsReviewedAndGoToNext()));
-    }
-
-    historyTable = new HistoryTable(this);
-
-    commitMessageBlock = new CommitMessageBlock();
-
-    topPanel = new FlowPanel();
-    add(topPanel);
-
-    contentTable = new UnifiedDiffTable();
-    contentTable.fileList = fileList;
-
-    topNav = new NavLinks(keysNavigation, patchKey.getParentKey());
-    bottomNav = new NavLinks(null, patchKey.getParentKey());
-
-    add(topNav);
-    contentPanel = new FlowPanel();
-    contentPanel.setStyleName(Gerrit.RESOURCES.css().unifiedTable());
-
-    contentPanel.add(contentTable);
-    add(contentPanel);
-    add(bottomNav);
-    if (Gerrit.isSignedIn()) {
-      add(reviewedPanels.bottom);
-    }
-
-    if (fileList != null) {
-      displayNav();
-    }
-  }
-
-  private void displayNav() {
-    DiffApi.diff(idSideB, patchKey.getFileName())
-      .base(idSideA)
-      .webLinksOnly()
-      .get(new GerritCallback<DiffInfo>() {
-        @Override
-        public void onSuccess(DiffInfo diffInfo) {
-          topNav.display(patchIndex, fileList,
-              getLinks(), getWebLinks(diffInfo));
-          bottomNav.display(patchIndex, fileList,
-              getLinks(), getWebLinks(diffInfo));
-        }
-      });
-  }
-
-  private List<InlineHyperlink> getLinks() {
-    InlineHyperlink toSideBySideDiffLink = new InlineHyperlink();
-    toSideBySideDiffLink.setHTML(new ImageResourceRenderer().render(Gerrit.RESOURCES.sideBySideDiff()));
-    toSideBySideDiffLink.setTargetHistoryToken(getSideBySideDiffUrl());
-    toSideBySideDiffLink.setTitle(PatchUtil.C.sideBySideDiff());
-    return Collections.singletonList(toSideBySideDiffLink);
-  }
-
-  private List<WebLinkInfo> getWebLinks(DiffInfo diffInfo) {
-    return diffInfo.unifiedWebLinks();
-  }
-
-  private String getSideBySideDiffUrl() {
-    return Dispatcher.toPatch("sidebyside", idSideA,
-        new Patch.Key(idSideB, patchKey.getFileName()));
-  }
-
-  @Override
-  protected void onLoad() {
-    super.onLoad();
-
-    if (patchSetDetail == null) {
-      PatchUtil.CHANGE_SVC.patchSetDetail(idSideB,
-          new GerritCallback<PatchSetDetail>() {
-            @Override
-            public void onSuccess(PatchSetDetail result) {
-              patchSetDetail = result;
-              if (fileList == null) {
-                fileList = new PatchTable(prefs);
-                fileList.display(idSideA, result);
-                patchIndex = fileList.indexOf(patchKey);
-              }
-              refresh(true);
-            }
-          });
-    } else {
-      refresh(true);
-    }
-  }
-
-  @Override
-  protected void onUnload() {
-    if (prefsHandler != null) {
-      prefsHandler.removeHandler();
-      prefsHandler = null;
-    }
-    if (regNavigation != null) {
-      regNavigation.removeHandler();
-      regNavigation = null;
-    }
-    if (regAction != null) {
-      regAction.removeHandler();
-      regAction = null;
-    }
-    super.onUnload();
-  }
-
-  @Override
-  public void registerKeys() {
-    super.registerKeys();
-    contentTable.setRegisterKeys(contentTable.isVisible());
-    if (regNavigation != null) {
-      regNavigation.removeHandler();
-      regNavigation = null;
-    }
-    regNavigation = GlobalKey.add(this, keysNavigation);
-    if (regAction != null) {
-      regAction.removeHandler();
-      regAction = null;
-    }
-    if (keysAction != null) {
-      regAction = GlobalKey.add(this, keysAction);
-    }
-  }
-
-  public PatchSet.Id getSideA() {
-    return idSideA;
-  }
-
-  public Patch.Key getPatchKey() {
-    return patchKey;
-  }
-
-  public int getPatchIndex() {
-    return patchIndex;
-  }
-
-  public PatchSetDetail getPatchSetDetail() {
-    return patchSetDetail;
-  }
-
-  public PatchTable getFileList() {
-    return fileList;
-  }
-
-  public TopView getTopView() {
-    return topView;
-  }
-
-  protected void refresh(final boolean isFirst) {
-    final int rpcseq = ++rpcSequence;
-    lastScript = null;
-    settingsPanel.setEnabled(false);
-    reviewedPanels.populate(patchKey, fileList, patchIndex);
-    if (isFirst && fileList != null && fileList.isLoaded()) {
-      fileList.movePointerTo(patchKey);
-    }
-
-    CallbackGroup cb = new CallbackGroup();
-    ConfigInfoCache.get(patchSetDetail.getProject(),
-        cb.add(new AsyncCallback<ConfigInfoCache.Entry>() {
-          @Override
-          public void onSuccess(ConfigInfoCache.Entry result) {
-            commentLinkProcessor = result.getCommentLinkProcessor();
-            contentTable.setCommentLinkProcessor(commentLinkProcessor);
-            setTheme(result.getTheme());
-          }
-
-          @Override
-          public void onFailure(Throwable caught) {
-            // Handled by ScreenLoadCallback.onFailure.
-          }
-        }));
-    PatchUtil.PATCH_SVC.patchScript(patchKey, idSideA, idSideB,
-        settingsPanel.getValue(), cb.addFinal(
-            new ScreenLoadCallback<PatchScript>(this) {
-              @Override
-              protected void preDisplay(final PatchScript result) {
-                if (rpcSequence == rpcseq) {
-                  onResult(result, isFirst);
-                }
-              }
-
-              @Override
-              public void onFailure(final Throwable caught) {
-                if (rpcSequence == rpcseq) {
-                  settingsPanel.setEnabled(true);
-                  super.onFailure(caught);
-                }
-              }
-        }));
-  }
-
-  private void onResult(final PatchScript script, final boolean isFirst) {
-    final String path = PatchTable.getDisplayFileName(patchKey);
-    String fileName = path;
-    final int last = fileName.lastIndexOf('/');
-    if (last >= 0) {
-      fileName = fileName.substring(last + 1);
-    }
-
-    setWindowTitle(fileName);
-    setPageTitle(path);
-
-    if (idSideB.equals(patchSetDetail.getPatchSet().getId())) {
-      commitMessageBlock.setVisible(true);
-      commitMessageBlock.display(patchSetDetail.getInfo().getMessage(),
-          commentLinkProcessor);
-    } else {
-      commitMessageBlock.setVisible(false);
-      PatchUtil.CHANGE_SVC.patchSetDetail(idSideB,
-          new GerritCallback<PatchSetDetail>() {
-            @Override
-            public void onSuccess(PatchSetDetail result) {
-              commitMessageBlock.setVisible(true);
-              commitMessageBlock.display(result.getInfo().getMessage(),
-                  commentLinkProcessor);
-            }
-          });
-    }
-
-    historyTable.display(script.getHistory());
-
-    for (Patch p : patchSetDetail.getPatches()) {
-      if (p.getKey().equals(patchKey)) {
-        if (p.getPatchType().equals(Patch.PatchType.BINARY)) {
-          contentTable.isDisplayBinary = true;
-        }
-        break;
-      }
-    }
-
-    if (script.isHugeFile()) {
-      DiffPreferencesInfo dp = script.getDiffPrefs();
-      int context = dp.context;
-      if (context == DiffPreferencesInfo.WHOLE_FILE_CONTEXT) {
-        context = Short.MAX_VALUE;
-      } else if (context > Short.MAX_VALUE) {
-        context = Short.MAX_VALUE;
-      }
-      dp.context = Math.min(context, LARGE_FILE_CONTEXT);
-      dp.syntaxHighlighting = false;
-      script.setDiffPrefs(dp);
-    }
-
-    contentTable.display(patchKey, idSideA, idSideB, script, patchSetDetail);
-    contentTable.display(script.getCommentDetail(), script.isExpandAllComments());
-    contentTable.finishDisplay();
-    contentTable.setRegisterKeys(isCurrentView());
-
-    settingsPanel.setEnableSmallFileFeatures(!script.isHugeFile());
-    settingsPanel.setEnableIntralineDifference(script.hasIntralineDifference());
-    settingsPanel.setEnabled(true);
-    lastScript = script;
-
-    if (fileList != null) {
-      displayNav();
-    }
-
-    if (Gerrit.isSignedIn()) {
-      boolean isReviewed = false;
-      if (isFirst && !prefs.get().manualReview) {
-        isReviewed = true;
-        reviewedPanels.setReviewedByCurrentUser(isReviewed);
-      } else {
-        for (Patch p : patchSetDetail.getPatches()) {
-          if (p.getKey().equals(patchKey)) {
-            isReviewed = p.isReviewedByCurrentUser();
-            break;
-          }
-        }
-      }
-      reviewedPanels.setValue(isReviewed);
-    }
-
-    intralineFailure = isFirst && script.hasIntralineFailure();
-    intralineTimeout = isFirst && script.hasIntralineTimeout();
-  }
-
-  @Override
-  public void onShowView() {
-    super.onShowView();
-    if (prefsHandler == null) {
-      prefsHandler = prefs.addValueChangeHandler(
-          new ValueChangeHandler<DiffPreferencesInfo>() {
-            @Override
-            public void onValueChange(ValueChangeEvent<DiffPreferencesInfo> event) {
-              update(event.getValue());
-            }
-          });
-    }
-    if (intralineFailure) {
-      intralineFailure = false;
-      new ErrorDialog(PatchUtil.C.intralineFailure()).show();
-    } else if (intralineTimeout) {
-      intralineTimeout = false;
-      new ErrorDialog(PatchUtil.C.intralineTimeout()).setText(
-          Gerrit.C.warnTitle()).show();
-    }
-    if (topView != null && prefs.get().retainHeader) {
-      setTopView(topView);
-    }
-  }
-
-  public void setTopView(TopView tv) {
-    topView = tv;
-    topPanel.clear();
-    switch(tv) {
-      case COMMIT:      topPanel.add(commitMessageBlock);
-        break;
-      case PREFERENCES: topPanel.add(settingsPanel);
-        break;
-      case PATCH_SETS:  topPanel.add(historyTable);
-        break;
-      case FILES:       topPanel.add(fileList);
-        break;
-      case MAIN:
-        break;
-    }
-  }
-
-  public class FileListCmd extends KeyCommand {
-    public FileListCmd(int mask, int key, String help) {
-      super(mask, key, help);
-    }
-
-    @Override
-    public void onKeyPress(final KeyPressEvent event) {
-      if (fileList == null || fileList.isAttached()) {
-        final PatchSet.Id psid = patchKey.getParentKey();
-        fileList = new PatchTable(prefs);
-        fileList.setSavePointerId("PatchTable " + psid);
-        PatchUtil.CHANGE_SVC.patchSetDetail(psid,
-            new GerritCallback<PatchSetDetail>() {
-              @Override
-              public void onSuccess(final PatchSetDetail result) {
-                fileList.display(idSideA, result);
-              }
-            });
-      }
-
-      final PatchBrowserPopup p = new PatchBrowserPopup(patchKey, fileList);
-      p.open();
-    }
-  }
-
-  public class ToggleReviewedCmd extends KeyCommand {
-    public ToggleReviewedCmd(int mask, int key, String help) {
-      super(mask, key, help);
-    }
-
-    @Override
-    public void onKeyPress(final KeyPressEvent event) {
-      final boolean isReviewed = !reviewedPanels.getValue();
-      reviewedPanels.setValue(isReviewed);
-      reviewedPanels.setReviewedByCurrentUser(isReviewed);
-    }
-  }
-
-  public class MarkAsReviewedAndGoToNextCmd extends KeyCommand {
-    public MarkAsReviewedAndGoToNextCmd(int mask, int key, String help) {
-      super(mask, key, help);
-    }
-
-    @Override
-    public void onKeyPress(final KeyPressEvent event) {
-      reviewedPanels.go();
-    }
-  }
-}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UpToChangeCommand.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UpToChangeCommand.java
deleted file mode 100644
index 970e33d3..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UpToChangeCommand.java
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (C) 2010 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.client.patches;
-
-import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.common.PageLinks;
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gwt.event.dom.client.KeyPressEvent;
-import com.google.gwtexpui.globalkey.client.KeyCommand;
-
-class UpToChangeCommand extends KeyCommand {
-  private final PatchSet.Id patchSetId;
-
-  UpToChangeCommand(PatchSet.Id patchSetId, int mask, int key) {
-    super(mask, key, PatchUtil.C.upToChange());
-    this.patchSetId = patchSetId;
-  }
-
-  @Override
-  public void onKeyPress(final KeyPressEvent event) {
-    Gerrit.display(PageLinks.toChange(patchSetId));
-  }
-}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ConfigInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ConfigInfo.java
index 322a354..96b25c5 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ConfigInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ConfigInfo.java
@@ -69,7 +69,7 @@
   public final native NativeMap<ActionInfo> actions()
   /*-{ return this.actions; }-*/;
 
-  private final native String submitTypeRaw()
+  private native String submitTypeRaw()
   /*-{ return this.submit_type }-*/;
 
   public final ProjectState state() {
@@ -78,13 +78,13 @@
     }
     return ProjectState.valueOf(stateRaw());
   }
-  private final native String stateRaw()
+  private native String stateRaw()
   /*-{ return this.state }-*/;
 
   public final native MaxObjectSizeLimitInfo maxObjectSizeLimit()
   /*-{ return this.max_object_size_limit; }-*/;
 
-  private final native NativeMap<CommentLinkInfo> commentlinks0()
+  private native NativeMap<CommentLinkInfo> commentlinks0()
   /*-{ return this.commentlinks; }-*/;
   final List<FindReplace> commentlinks() {
     JsArray<CommentLinkInfo> cls = commentlinks0().values();
@@ -143,7 +143,7 @@
     public final InheritableBoolean configuredValue() {
       return InheritableBoolean.valueOf(configuredValueRaw());
     }
-    private final native String configuredValueRaw()
+    private native String configuredValueRaw()
     /*-{ return this.configured_value }-*/;
 
     public final void setConfiguredValue(InheritableBoolean v) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java
index fffdd3f..8e29e4c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java
@@ -228,43 +228,43 @@
     final void setUseContributorAgreements(InheritableBoolean v) {
       setUseContributorAgreementsRaw(v.name());
     }
-    private final native void setUseContributorAgreementsRaw(String v)
+    private native void setUseContributorAgreementsRaw(String v)
     /*-{ if(v)this.use_contributor_agreements=v; }-*/;
 
     final void setUseContentMerge(InheritableBoolean v) {
       setUseContentMergeRaw(v.name());
     }
-    private final native void setUseContentMergeRaw(String v)
+    private native void setUseContentMergeRaw(String v)
     /*-{ if(v)this.use_content_merge=v; }-*/;
 
     final void setUseSignedOffBy(InheritableBoolean v) {
       setUseSignedOffByRaw(v.name());
     }
-    private final native void setUseSignedOffByRaw(String v)
+    private native void setUseSignedOffByRaw(String v)
     /*-{ if(v)this.use_signed_off_by=v; }-*/;
 
     final void setRequireChangeId(InheritableBoolean v) {
       setRequireChangeIdRaw(v.name());
     }
-    private final native void setRequireChangeIdRaw(String v)
+    private native void setRequireChangeIdRaw(String v)
     /*-{ if(v)this.require_change_id=v; }-*/;
 
     final void setCreateNewChangeForAllNotInTarget(InheritableBoolean v) {
       setCreateNewChangeForAllNotInTargetRaw(v.name());
     }
-    private final native void setCreateNewChangeForAllNotInTargetRaw(String v)
+    private native void setCreateNewChangeForAllNotInTargetRaw(String v)
     /*-{ if(v)this.create_new_change_for_all_not_in_target=v; }-*/;
 
     final void setEnableSignedPush(InheritableBoolean v) {
       setEnableSignedPushRaw(v.name());
     }
-    private final native void setEnableSignedPushRaw(String v)
+    private native void setEnableSignedPushRaw(String v)
     /*-{ if(v)this.enable_signed_push=v; }-*/;
 
     final void setRequireSignedPush(InheritableBoolean v) {
       setRequireSignedPushRaw(v.name());
     }
-    private final native void setRequireSignedPushRaw(String v)
+    private native void setRequireSignedPushRaw(String v)
     /*-{ if(v)this.require_signed_push=v; }-*/;
 
     final native void setMaxObjectSizeLimit(String l)
@@ -273,13 +273,13 @@
     final void setSubmitType(SubmitType t) {
       setSubmitTypeRaw(t.name());
     }
-    private final native void setSubmitTypeRaw(String t)
+    private native void setSubmitTypeRaw(String t)
     /*-{ if(t)this.submit_type=t; }-*/;
 
     final void setState(ProjectState s) {
       setStateRaw(s.name());
     }
-    private final native void setStateRaw(String s)
+    private native void setStateRaw(String s)
     /*-{ if(s)this.state=s; }-*/;
 
     final void setPluginConfigValues(Map<String, Map<String, ConfigParameterValue>> pluginConfigValues) {
@@ -295,7 +295,7 @@
         setPluginConfigValuesRaw(configValues);
       }
     }
-    private final native void setPluginConfigValuesRaw(NativeMap<ConfigParameterValueMap> v)
+    private native void setPluginConfigValuesRaw(NativeMap<ConfigParameterValueMap> v)
     /*-{ this.plugin_config_values=v; }-*/;
   }
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectInfo.java
index 00a4034..eed9d1d 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectInfo.java
@@ -36,7 +36,7 @@
     return ProjectState.valueOf(getStringState());
   }
 
-  private final native String getStringState() /*-{ return this.state; }-*/;
+  private native String getStringState() /*-{ return this.state; }-*/;
 
   @Override
   public final String getDisplayString() {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/RpcConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/RpcConstants.java
index 89e9367..620133d 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/RpcConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/RpcConstants.java
@@ -18,7 +18,7 @@
 import com.google.gwt.i18n.client.Constants;
 
 public interface RpcConstants extends Constants {
-  public static final RpcConstants C = GWT.create(RpcConstants.class);
+  RpcConstants C = GWT.create(RpcConstants.class);
 
   String errorServerUnavailable();
   String errorRemoteJsonException();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ChangeLink.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ChangeLink.java
index 241b354..1ae4489 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ChangeLink.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ChangeLink.java
@@ -17,7 +17,6 @@
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gwt.core.client.GWT;
 
 public class ChangeLink extends InlineHyperlink {
@@ -26,19 +25,11 @@
   }
 
   protected Change.Id cid;
-  protected PatchSet.Id psid;
 
   public ChangeLink(final String text, final Change.Id c) {
     super(text, PageLinks.toChange(c));
     getElement().setPropertyString("href", permalink(c));
     cid = c;
-    psid = null;
-  }
-
-  public ChangeLink(final String text, final PatchSet.Id ps) {
-    super(text, PageLinks.toChange(ps));
-    cid = ps.getParentKey();
-    psid = ps;
   }
 
   @Override
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CherryPickDialog.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CherryPickDialog.java
index f69e042..4e6f500 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CherryPickDialog.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CherryPickDialog.java
@@ -85,7 +85,7 @@
   static class BranchSuggestion implements Suggestion {
     private BranchInfo branch;
 
-    public BranchSuggestion(BranchInfo branch) {
+    BranchSuggestion(BranchInfo branch) {
       this.branch = branch;
     }
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CommentedActionDialog.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CommentedActionDialog.java
index 60b5f93..c21d5dc 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CommentedActionDialog.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CommentedActionDialog.java
@@ -35,7 +35,7 @@
   protected final FlowPanel contentPanel;
   protected FocusWidget focusOn;
 
-  protected boolean sent = false;
+  protected boolean sent;
 
   public CommentedActionDialog(final String title, final String heading) {
     super(/* auto hide */false, /* modal */true);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CreateChangeDialog.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CreateChangeDialog.java
index e398e78..7cda8a3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CreateChangeDialog.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CreateChangeDialog.java
@@ -98,7 +98,7 @@
   static class BranchSuggestion implements Suggestion {
     private BranchInfo branch;
 
-    public BranchSuggestion(BranchInfo branch) {
+    BranchSuggestion(BranchInfo branch) {
       this.branch = branch;
     }
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FancyFlexTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FancyFlexTable.java
index 88ee293..e77bc10 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FancyFlexTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FancyFlexTable.java
@@ -222,9 +222,9 @@
   protected static class MyFlexTable extends FlexTable {
   }
 
-  private static final native <ItemType> void setRowItem(Element td, ItemType c)
+  private static native <ItemType> void setRowItem(Element td, ItemType c)
   /*-{ td['__gerritRowItem'] = c; }-*/;
 
-  private static final native <ItemType> ItemType getRowItem(Element td)
+  private static native <ItemType> ItemType getRowItem(Element td)
   /*-{ return td['__gerritRowItem']; }-*/;
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/MorphingTabPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/MorphingTabPanel.java
index db7ad3c..1b99707 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/MorphingTabPanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/MorphingTabPanel.java
@@ -81,7 +81,7 @@
 
         /* Re-insert the widget right after the first visible widget found
            when scanning backwards from the current widget */
-        for (int pos = origPos -1; pos >=0 ; pos--) {
+        for (int pos = origPos - 1; pos >= 0 ; pos--) {
           int visiblePos = visibles.indexOf(widgets.get(pos));
           if (visiblePos != -1) {
             visibles.add(visiblePos + 1, w);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/RebaseDialog.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/RebaseDialog.java
index 1a9fc4b..77c4e56 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/RebaseDialog.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/RebaseDialog.java
@@ -147,7 +147,7 @@
   private static class ChangeSuggestion implements Suggestion {
     private ChangeInfo change;
 
-    public ChangeSuggestion(ChangeInfo change) {
+    ChangeSuggestion(ChangeInfo change) {
       this.change = change;
     }
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Screen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Screen.java
index 5192d6d..1068b3e 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Screen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Screen.java
@@ -70,7 +70,7 @@
   public void registerKeys() {
   }
 
-  private static enum Cols {
+  private enum Cols {
     West, Title, East, FarEast
   }
 
@@ -184,7 +184,6 @@
     if (windowTitle != null) {
       Gerrit.setWindowTitle(this, windowTitle);
     }
-    Gerrit.updateMenus(this);
     Gerrit.EVENT_BUS.fireEvent(new ScreenLoadEvent(this));
     Gerrit.setQueryString(null);
     registerKeys();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ScreenLoadEvent.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ScreenLoadEvent.java
index 45ba808..debd9a6 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ScreenLoadEvent.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ScreenLoadEvent.java
@@ -36,7 +36,7 @@
     return TYPE;
   }
 
-  public Screen getScreen(){
+  public Screen getScreen() {
     return screen;
   }
 }
diff --git a/gerrit-gwtui/src/main/java/net/codemirror/lib/CodeMirror.java b/gerrit-gwtui/src/main/java/net/codemirror/lib/CodeMirror.java
index ee4c050..eccde6f 100644
--- a/gerrit-gwtui/src/main/java/net/codemirror/lib/CodeMirror.java
+++ b/gerrit-gwtui/src/main/java/net/codemirror/lib/CodeMirror.java
@@ -138,7 +138,7 @@
     addLineClassNative(line, where.value(), className);
   }
 
-  private final native void addLineClassNative(int line, String where,
+  private native void addLineClassNative(int line, String where,
       String lineClass) /*-{
     this.addLineClass(line, where, lineClass)
   }-*/;
@@ -148,7 +148,7 @@
     addLineClassNative(line, where.value(), className);
   }
 
-  private final native void addLineClassNative(LineHandle line, String where,
+  private native void addLineClassNative(LineHandle line, String where,
       String lineClass) /*-{
     this.addLineClass(line, where, lineClass)
   }-*/;
@@ -158,7 +158,7 @@
     removeLineClassNative(line, where.value(), className);
   }
 
-  private final native void removeLineClassNative(int line, String where,
+  private native void removeLineClassNative(int line, String where,
       String lineClass) /*-{
     this.removeLineClass(line, where, lineClass)
   }-*/;
@@ -168,7 +168,7 @@
     removeLineClassNative(line, where.value(), className);
   }
 
-  private final native void removeLineClassNative(LineHandle line, String where,
+  private native void removeLineClassNative(LineHandle line, String where,
       String lineClass) /*-{
     this.removeLineClass(line, where, lineClass)
   }-*/;
diff --git a/gerrit-gwtui/src/main/java/net/codemirror/lib/Extras.java b/gerrit-gwtui/src/main/java/net/codemirror/lib/Extras.java
index 13186d1..f2fc074 100644
--- a/gerrit-gwtui/src/main/java/net/codemirror/lib/Extras.java
+++ b/gerrit-gwtui/src/main/java/net/codemirror/lib/Extras.java
@@ -30,7 +30,7 @@
 /** Additional features added to CodeMirror by Gerrit Code Review. */
 public class Extras {
   static final native Extras get(CodeMirror c) /*-{ return c.gerritExtras }-*/;
-  private static final native void set(CodeMirror c, Extras e)
+  private static native void set(CodeMirror c, Extras e)
   /*-{ c.gerritExtras = e }-*/;
 
   static void attach(CodeMirror c) {
diff --git a/gerrit-gwtui/src/main/java/net/codemirror/lib/Lib.java b/gerrit-gwtui/src/main/java/net/codemirror/lib/Lib.java
index a3b1cf4..f205ef9 100644
--- a/gerrit-gwtui/src/main/java/net/codemirror/lib/Lib.java
+++ b/gerrit-gwtui/src/main/java/net/codemirror/lib/Lib.java
@@ -21,7 +21,7 @@
 import com.google.gwt.resources.client.ExternalTextResource;
 
 interface Lib extends ClientBundle {
-  static final Lib I = GWT.create(Lib.class);
+  Lib I = GWT.create(Lib.class);
 
   @Source("cm.css")
   ExternalTextResource css();
diff --git a/gerrit-gwtui/src/main/java/net/codemirror/lib/Vim.java b/gerrit-gwtui/src/main/java/net/codemirror/lib/Vim.java
index f1dee69..c3d58c9ba 100644
--- a/gerrit-gwtui/src/main/java/net/codemirror/lib/Vim.java
+++ b/gerrit-gwtui/src/main/java/net/codemirror/lib/Vim.java
@@ -32,7 +32,7 @@
     }
     for (String key : new String[] {
       "Ctrl-C", "Ctrl-O", "Ctrl-P", "Ctrl-S",
-      "Ctrl-F", "Ctrl-B", "Ctrl-R"}) {
+      "Ctrl-F", "Ctrl-B", "Ctrl-R",}) {
       km.propagate(key);
     }
     for (int i = 0; i <= 9; i++) {
diff --git a/gerrit-gwtui/src/main/java/net/codemirror/mode/ModeInfo.java b/gerrit-gwtui/src/main/java/net/codemirror/mode/ModeInfo.java
index 9c82c06..697f4e1 100644
--- a/gerrit-gwtui/src/main/java/net/codemirror/mode/ModeInfo.java
+++ b/gerrit-gwtui/src/main/java/net/codemirror/mode/ModeInfo.java
@@ -258,7 +258,7 @@
   public final native JsArrayString mimes()
   /*-{ return this.mimes || [this.mime] }-*/;
 
-  private final native JsArrayString ext()
+  private native JsArrayString ext()
   /*-{ return this.ext || [] }-*/;
 
   protected ModeInfo() {
diff --git a/gerrit-gwtui/src/main/java/net/codemirror/mode/Modes.java b/gerrit-gwtui/src/main/java/net/codemirror/mode/Modes.java
index 593dc29..3f7c629 100644
--- a/gerrit-gwtui/src/main/java/net/codemirror/mode/Modes.java
+++ b/gerrit-gwtui/src/main/java/net/codemirror/mode/Modes.java
@@ -20,7 +20,7 @@
 import com.google.gwt.resources.client.DataResource.DoNotEmbed;
 
 public interface Modes extends ClientBundle {
-  public static final Modes I = GWT.create(Modes.class);
+  Modes I = GWT.create(Modes.class);
 
   @Source("apl.js") @DoNotEmbed DataResource apl();
   @Source("asciiarmor.js") @DoNotEmbed DataResource asciiarmor();
diff --git a/gerrit-gwtui/src/main/java/net/codemirror/theme/ThemeLoader.java b/gerrit-gwtui/src/main/java/net/codemirror/theme/ThemeLoader.java
index c563c0a..040b382 100644
--- a/gerrit-gwtui/src/main/java/net/codemirror/theme/ThemeLoader.java
+++ b/gerrit-gwtui/src/main/java/net/codemirror/theme/ThemeLoader.java
@@ -69,7 +69,7 @@
     }
   }
 
-  private static final ExternalTextResource findTheme(Theme theme) {
+  private static ExternalTextResource findTheme(Theme theme) {
     for (ExternalTextResource r : THEMES) {
       if (theme.name().toLowerCase().equals(r.getName())) {
         return r;
diff --git a/gerrit-gwtui/src/main/java/net/codemirror/theme/Themes.java b/gerrit-gwtui/src/main/java/net/codemirror/theme/Themes.java
index ed0ffca..3a66480 100644
--- a/gerrit-gwtui/src/main/java/net/codemirror/theme/Themes.java
+++ b/gerrit-gwtui/src/main/java/net/codemirror/theme/Themes.java
@@ -19,7 +19,7 @@
 import com.google.gwt.resources.client.ExternalTextResource;
 
 public interface Themes extends ClientBundle {
-  public static final Themes I = GWT.create(Themes.class);
+  Themes I = GWT.create(Themes.class);
 
   @Source("eclipse.css") ExternalTextResource eclipse();
   @Source("elegant.css") ExternalTextResource elegant();
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpModule.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpModule.java
index ab6cc90..5146b31 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpModule.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpModule.java
@@ -60,7 +60,7 @@
     filter("/a/*").through(authFilter);
   }
 
-  private boolean isHttpEnabled(){
+  private boolean isHttpEnabled() {
     return downloadConfig.getDownloadSchemes().contains(CoreDownloadSchemes.ANON_HTTP)
         || downloadConfig.getDownloadSchemes().contains(CoreDownloadSchemes.HTTP);
   }
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java
index 13b1a48..bf8fe01 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java
@@ -98,7 +98,7 @@
 
     private final boolean enableReceive;
 
-    public Module(boolean enableReceive) {
+    Module(boolean enableReceive) {
       this.enableReceive = enableReceive;
     }
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/LoginUrlToken.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/LoginUrlToken.java
index 177ff04..41acfa2 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/LoginUrlToken.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/LoginUrlToken.java
@@ -23,7 +23,7 @@
 public class LoginUrlToken {
   private static final String DEFAULT_TOKEN = '#' + PageLinks.MINE;
 
-  public static String getToken(final HttpServletRequest req){
+  public static String getToken(final HttpServletRequest req) {
     String token = req.getPathInfo();
     if (Strings.isNullOrEmpty(token)) {
       return DEFAULT_TOKEN;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectDigestFilter.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectDigestFilter.java
index 38dd118..3ff060c 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectDigestFilter.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectDigestFilter.java
@@ -212,7 +212,7 @@
 
   private static final char[] LHEX =
       {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', //
-          'a', 'b', 'c', 'd', 'e', 'f'};
+          'a', 'b', 'c', 'd', 'e', 'f',};
 
   private static String LHEX(byte[] bin) {
     StringBuilder r = new StringBuilder(bin.length * 2);
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectOAuthFilter.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectOAuthFilter.java
index e80b5ab..7cadbae37 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectOAuthFilter.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectOAuthFilter.java
@@ -221,7 +221,7 @@
       throw new ServletException("OAuth login provider configuration is"
           + " invalid: Must be of the form pluginName:providerName");
     }
-    defaultAuthPlugin= gitOAuthProvider.substring(0, splitPos);
+    defaultAuthPlugin = gitOAuthProvider.substring(0, splitPos);
     defaultAuthProvider = gitOAuthProvider.substring(splitPos + 1);
     OAuthLoginProvider provider = loginProviders.get(defaultAuthPlugin,
         defaultAuthProvider);
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java
index 422a83d..3e3b7c4 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java
@@ -16,8 +16,6 @@
 
 import static com.google.gerrit.extensions.registration.PrivateInternals_DynamicTypes.registerInParentInjectors;
 
-import com.google.gerrit.extensions.registration.DynamicSet;
-import com.google.gerrit.extensions.webui.WebUiPlugin;
 import com.google.gerrit.httpd.auth.become.BecomeAnyAccountModule;
 import com.google.gerrit.httpd.auth.container.HttpAuthModule;
 import com.google.gerrit.httpd.auth.container.HttpsClientSslCertModule;
@@ -71,8 +69,6 @@
       install(new GitwebModule());
     }
 
-    DynamicSet.setOf(binder(), WebUiPlugin.class);
-
     install(new AsyncReceiveCommits.Module());
 
     bind(SocketAddress.class).annotatedWith(RemotePeer.class).toProvider(
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/container/HttpAuthFilter.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/container/HttpAuthFilter.java
index 88abe84..f492d44 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/container/HttpAuthFilter.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/container/HttpAuthFilter.java
@@ -157,7 +157,7 @@
   }
 
   String getRemoteExternalIdToken(HttpServletRequest req) {
-    if(externalIdHeader != null) {
+    if (externalIdHeader != null) {
       return emptyToNull(req.getHeader(externalIdHeader));
     } else {
       return null;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/ContextMapper.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/ContextMapper.java
index 6afe52a..b51bfb9 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/ContextMapper.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/ContextMapper.java
@@ -25,7 +25,7 @@
   private final String base;
   private final String authorizedBase;
 
-  public ContextMapper(String contextPath) {
+  ContextMapper(String contextPath) {
     base = Strings.nullToEmpty(contextPath) + PLUGINS_PREFIX;
     authorizedBase = Strings.nullToEmpty(contextPath) + AUTHORIZED_PREFIX;
   }
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpAutoRegisterModuleGenerator.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpAutoRegisterModuleGenerator.java
index 0e81a0d..d1c617f 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpAutoRegisterModuleGenerator.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpAutoRegisterModuleGenerator.java
@@ -14,18 +14,14 @@
 
 package com.google.gerrit.httpd.plugins;
 
-import static com.google.common.base.Preconditions.checkState;
 import static com.google.gerrit.server.plugins.AutoRegisterUtil.calculateBindAnnotation;
 
 import com.google.common.collect.LinkedListMultimap;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Multimap;
 import com.google.gerrit.extensions.annotations.Export;
-import com.google.gerrit.extensions.registration.DynamicSet;
-import com.google.gerrit.extensions.webui.JavaScriptPlugin;
-import com.google.gerrit.extensions.webui.WebUiPlugin;
-import com.google.gerrit.server.plugins.HttpModuleGenerator;
 import com.google.gerrit.server.plugins.InvalidPluginException;
+import com.google.gerrit.server.plugins.ModuleGenerator;
 import com.google.inject.Module;
 import com.google.inject.Scopes;
 import com.google.inject.TypeLiteral;
@@ -37,10 +33,9 @@
 import javax.servlet.http.HttpServlet;
 
 class HttpAutoRegisterModuleGenerator extends ServletModule
-    implements HttpModuleGenerator {
+    implements ModuleGenerator {
   private final Map<String, Class<HttpServlet>> serve = Maps.newHashMap();
   private final Multimap<TypeLiteral<?>, Class<?>> listeners = LinkedListMultimap.create();
-  private String javascript;
 
   @Override
   protected void configureServlets() {
@@ -58,10 +53,6 @@
       Annotation n = calculateBindAnnotation(impl);
       bind(type).annotatedWith(n).to(impl);
     }
-    if (javascript != null) {
-      DynamicSet.bind(binder(), WebUiPlugin.class).toInstance(
-          new JavaScriptPlugin(javascript));
-    }
   }
 
   @Override
@@ -89,14 +80,6 @@
   }
 
   @Override
-  public void export(String javascript) {
-    checkState(this.javascript == null,
-        "Multiple JavaScript plugins detected: %s, %s", this.javascript,
-        javascript);
-    this.javascript = javascript;
-  }
-
-  @Override
   public void listen(TypeLiteral<?> tl, Class<?> clazz) {
     listeners.put(tl, clazz);
   }
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginModule.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginModule.java
index 6b66bbd..3c72ec5 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginModule.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginModule.java
@@ -18,7 +18,7 @@
 import com.google.gerrit.httpd.resources.ResourceKey;
 import com.google.gerrit.httpd.resources.ResourceWeigher;
 import com.google.gerrit.server.cache.CacheModule;
-import com.google.gerrit.server.plugins.HttpModuleGenerator;
+import com.google.gerrit.server.plugins.ModuleGenerator;
 import com.google.gerrit.server.plugins.ReloadPluginListener;
 import com.google.gerrit.server.plugins.StartPluginListener;
 import com.google.inject.internal.UniqueAnnotations;
@@ -51,7 +51,7 @@
       .annotatedWith(UniqueAnnotations.create())
       .to(LfsPluginServlet.class);
 
-    bind(HttpModuleGenerator.class)
+    bind(ModuleGenerator.class)
       .to(HttpAutoRegisterModuleGenerator.class);
 
     install(new CacheModule() {
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java
index 4e635b2..a4cd623 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java
@@ -125,7 +125,7 @@
       int c = host.lastIndexOf(':');
       if (0 <= c) {
         sshHost = host.substring(0, c);
-        sshPort = Integer.parseInt(host.substring(c+1));
+        sshPort = Integer.parseInt(host.substring(c + 1));
       } else {
         sshHost = host;
         sshPort = 22;
@@ -346,7 +346,7 @@
       int nameOffset) throws IOException {
     if (!entries.isEmpty()) {
       md.append("## ").append(sectionTitle).append(" ##\n");
-      for(PluginEntry entry : entries) {
+      for (PluginEntry entry : entries) {
         String rsrc = entry.getName().substring(prefix.length());
         String entryTitle;
         if (rsrc.endsWith(".html")) {
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/PluginServletContext.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/PluginServletContext.java
index af34c5f..0889c85 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/PluginServletContext.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/PluginServletContext.java
@@ -208,7 +208,7 @@
     }
   }
 
-  static interface API {
+  interface API {
     String getContextPath();
     String getInitParameter(String name);
     @SuppressWarnings("rawtypes")
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/ResourceServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/ResourceServlet.java
index d9aab24..05990e9 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/ResourceServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/ResourceServlet.java
@@ -205,6 +205,10 @@
   Resource getResource(String name) {
     try {
       Path p = getResourcePath(name);
+      if (p == null) {
+        log.warn(String.format("Path doesn't exist %s", name));
+        return null;
+      }
       return cache.get(p, newLoader(p));
     } catch (ExecutionException | IOException e) {
       log.warn(String.format("Cannot load static resource %s", name), e);
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/SingleFileServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/SingleFileServlet.java
index d75a523..111145f 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/SingleFileServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/SingleFileServlet.java
@@ -19,7 +19,7 @@
 import java.nio.file.Path;
 
 /** Serve a single static file, regardless of path. */
-class SingleFileServlet extends ResourceServlet{
+class SingleFileServlet extends ResourceServlet {
   private static final long serialVersionUID = 1L;
 
   private final Path path;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/RestApiServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
index c6ae883..660dbbb 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
@@ -796,7 +796,7 @@
       final BinaryResult src) throws IOException {
     TemporaryBuffer.Heap buf = heap(HEAP_EST_SIZE, Integer.MAX_VALUE);
     buf.write(JSON_MAGIC);
-    try(Writer w = new BufferedWriter(new OutputStreamWriter(buf, UTF_8));
+    try (Writer w = new BufferedWriter(new OutputStreamWriter(buf, UTF_8));
         JsonWriter json = new JsonWriter(w)) {
       json.setLenient(true);
       json.setHtmlSafe(true);
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/BaseServiceImplementation.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/BaseServiceImplementation.java
index 3c1c6e9..c89d7ca 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/BaseServiceImplementation.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/BaseServiceImplementation.java
@@ -121,7 +121,7 @@
   }
 
   /** Arbitrary action to run with a database connection. */
-  public static interface Action<T> {
+  public interface Action<T> {
     /**
      * Perform this action, returning the onSuccess value.
      *
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/UiRpcModule.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/UiRpcModule.java
index f3577b9..4398c78 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/UiRpcModule.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/UiRpcModule.java
@@ -15,8 +15,6 @@
 package com.google.gerrit.httpd.rpc;
 
 import com.google.gerrit.httpd.rpc.account.AccountModule;
-import com.google.gerrit.httpd.rpc.changedetail.ChangeModule;
-import com.google.gerrit.httpd.rpc.patch.PatchModule;
 import com.google.gerrit.httpd.rpc.project.ProjectModule;
 
 /** Registers servlets to answer RPCs from client UI. */
@@ -30,8 +28,6 @@
     rpc(SystemInfoServiceImpl.class);
 
     install(new AccountModule());
-    install(new ChangeModule());
-    install(new PatchModule());
     install(new ProjectModule());
   }
 }
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountServiceImpl.java
index a8c5210..8d3947f 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountServiceImpl.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountServiceImpl.java
@@ -74,7 +74,7 @@
   @Override
   public void changeDiffPreferences(final DiffPreferencesInfo diffPref,
       AsyncCallback<VoidResult> callback) {
-    run(callback, new Action<VoidResult>(){
+    run(callback, new Action<VoidResult>() {
       @Override
       public VoidResult run(ReviewDb db) throws OrmException {
         if (!getUser().isIdentifiedUser()) {
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailServiceImpl.java
deleted file mode 100644
index 37ca524..0000000
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailServiceImpl.java
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (C) 2008 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.httpd.rpc.changedetail;
-
-import com.google.gerrit.common.data.ChangeDetailService;
-import com.google.gerrit.common.data.PatchSetDetail;
-import com.google.gerrit.extensions.client.DiffPreferencesInfo;
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gwtjsonrpc.common.AsyncCallback;
-import com.google.inject.Inject;
-
-class ChangeDetailServiceImpl implements ChangeDetailService {
-  private final PatchSetDetailFactory.Factory patchSetDetail;
-
-  @Inject
-  ChangeDetailServiceImpl(
-      final PatchSetDetailFactory.Factory patchSetDetail) {
-    this.patchSetDetail = patchSetDetail;
-  }
-
-  @Override
-  public void patchSetDetail(PatchSet.Id id,
-      AsyncCallback<PatchSetDetail> callback) {
-    patchSetDetail2(null, id, null, callback);
-  }
-
-  @Override
-  public void patchSetDetail2(PatchSet.Id baseId, PatchSet.Id id,
-      DiffPreferencesInfo diffPrefs, AsyncCallback<PatchSetDetail> callback) {
-    patchSetDetail.create(baseId, id, diffPrefs).to(callback);
-  }
-}
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeModule.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeModule.java
deleted file mode 100644
index d8adfe3..0000000
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeModule.java
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (C) 2009 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.httpd.rpc.changedetail;
-
-import com.google.gerrit.extensions.config.FactoryModule;
-import com.google.gerrit.httpd.rpc.RpcServletModule;
-import com.google.gerrit.httpd.rpc.UiRpcModule;
-
-public class ChangeModule extends RpcServletModule {
-  public ChangeModule() {
-    super(UiRpcModule.PREFIX);
-  }
-
-  @Override
-  protected void configureServlets() {
-    install(new FactoryModule() {
-      @Override
-      protected void configure() {
-        factory(PatchSetDetailFactory.Factory.class);
-      }
-    });
-    rpc(ChangeDetailServiceImpl.class);
-  }
-}
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetDetailFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetDetailFactory.java
deleted file mode 100644
index 1f71b86..0000000
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetDetailFactory.java
+++ /dev/null
@@ -1,234 +0,0 @@
-// Copyright (C) 2008 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.httpd.rpc.changedetail;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-import com.google.common.base.Optional;
-import com.google.gerrit.common.Nullable;
-import com.google.gerrit.common.data.PatchSetDetail;
-import com.google.gerrit.common.errors.NoSuchEntityException;
-import com.google.gerrit.extensions.client.DiffPreferencesInfo;
-import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
-import com.google.gerrit.extensions.restapi.AuthException;
-import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.reviewdb.client.AccountPatchReview;
-import com.google.gerrit.reviewdb.client.Patch;
-import com.google.gerrit.reviewdb.client.PatchLineComment;
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gerrit.server.CurrentUser;
-import com.google.gerrit.server.PatchLineCommentsUtil;
-import com.google.gerrit.server.PatchSetUtil;
-import com.google.gerrit.server.edit.ChangeEdit;
-import com.google.gerrit.server.edit.ChangeEditUtil;
-import com.google.gerrit.server.notedb.ChangeNotes;
-import com.google.gerrit.server.patch.PatchList;
-import com.google.gerrit.server.patch.PatchListCache;
-import com.google.gerrit.server.patch.PatchListKey;
-import com.google.gerrit.server.patch.PatchListNotAvailableException;
-import com.google.gerrit.server.patch.PatchSetInfoFactory;
-import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
-import com.google.gerrit.server.project.ChangeControl;
-import com.google.gerrit.server.project.NoSuchChangeException;
-import com.google.gwtorm.server.OrmException;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import com.google.inject.assistedinject.Assisted;
-
-import org.eclipse.jgit.lib.ObjectId;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/** Creates a {@link PatchSetDetail} from a {@link PatchSet}. */
-class PatchSetDetailFactory extends Handler<PatchSetDetail> {
-
-  private static final Logger log =
-    LoggerFactory.getLogger(PatchSetDetailFactory.class);
-
-  interface Factory {
-    PatchSetDetailFactory create(
-        @Assisted("psIdBase") @Nullable PatchSet.Id psIdBase,
-        @Assisted("psIdNew") PatchSet.Id psIdNew,
-        @Nullable DiffPreferencesInfo diffPrefs);
-  }
-
-  private final PatchSetInfoFactory infoFactory;
-  private final ReviewDb db;
-  private final PatchListCache patchListCache;
-  private final Provider<CurrentUser> userProvider;
-  private final ChangeControl.GenericFactory changeControlFactory;
-  private final PatchLineCommentsUtil plcUtil;
-  private final PatchSetUtil psUtil;
-  private final ChangeEditUtil editUtil;
-
-  private Project.NameKey project;
-  private final PatchSet.Id psIdBase;
-  private final PatchSet.Id psIdNew;
-  private final DiffPreferencesInfo diffPrefs;
-  private ObjectId oldId;
-  private ObjectId newId;
-
-  private PatchSetDetail detail;
-  ChangeControl control;
-  PatchSet patchSet;
-
-  @Inject
-  PatchSetDetailFactory(final PatchSetInfoFactory psif, final ReviewDb db,
-      final PatchListCache patchListCache,
-      final Provider<CurrentUser> userProvider,
-      final ChangeControl.GenericFactory changeControlFactory,
-      final PatchLineCommentsUtil plcUtil,
-      final PatchSetUtil psUtil,
-      ChangeEditUtil editUtil,
-      @Assisted("psIdBase") @Nullable final PatchSet.Id psIdBase,
-      @Assisted("psIdNew") final PatchSet.Id psIdNew,
-      @Assisted @Nullable final DiffPreferencesInfo diffPrefs) {
-    this.infoFactory = psif;
-    this.db = db;
-    this.patchListCache = patchListCache;
-    this.userProvider = userProvider;
-    this.changeControlFactory = changeControlFactory;
-    this.plcUtil = plcUtil;
-    this.psUtil = psUtil;
-    this.editUtil = editUtil;
-
-    this.psIdBase = psIdBase;
-    this.psIdNew = psIdNew;
-    if (psIdBase != null && psIdNew != null) {
-      checkArgument(psIdBase.getParentKey().equals(psIdNew.getParentKey()),
-          "cannot compare PatchSets from different changes: %s and %s",
-          psIdBase, psIdNew);
-    }
-    this.diffPrefs = diffPrefs;
-  }
-
-  @Override
-  public PatchSetDetail call() throws OrmException, NoSuchEntityException,
-      PatchSetInfoNotAvailableException, NoSuchChangeException, AuthException,
-      IOException {
-    Optional<ChangeEdit> edit = null;
-    ChangeNotes notes;
-    if (control == null || patchSet == null) {
-      control = changeControlFactory.validateFor(db, psIdNew.getParentKey(),
-          userProvider.get());
-      notes = control.getNotes();
-      if (psIdNew.get() == 0) {
-        edit = editUtil.byChange(control.getChange());
-        if (edit.isPresent()) {
-          patchSet = edit.get().getBasePatchSet();
-        }
-      } else {
-        patchSet = psUtil.get(db, notes, psIdNew);
-      }
-      if (patchSet == null) {
-        throw new NoSuchEntityException();
-      }
-    } else {
-      notes = control.getNotes();
-    }
-    project = control.getProject().getNameKey();
-    final PatchList list;
-
-    try {
-      if (psIdBase != null) {
-        oldId = toObjectId(psUtil.get(db, notes, psIdBase));
-        if (edit != null && edit.isPresent()) {
-          newId = edit.get().getEditCommit().toObjectId();
-        } else {
-          newId = toObjectId(patchSet);
-        }
-
-        list = listFor(keyFor(diffPrefs.ignoreWhitespace));
-      } else { // OK, means use base to compare
-        list = patchListCache.get(control.getChange(), patchSet);
-      }
-    } catch (PatchListNotAvailableException e) {
-      throw new NoSuchEntityException();
-    }
-
-    final List<Patch> patches = list.toPatchList(patchSet.getId());
-    final Map<Patch.Key, Patch> byKey = new HashMap<>();
-    for (final Patch p : patches) {
-      byKey.put(p.getKey(), p);
-    }
-
-    if (edit == null) {
-      for (PatchLineComment c : plcUtil.publishedByPatchSet(db, notes, psIdNew)) {
-        final Patch p = byKey.get(c.getKey().getParentKey());
-        if (p != null) {
-          p.setCommentCount(p.getCommentCount() + 1);
-        }
-      }
-    }
-
-    detail = new PatchSetDetail();
-    detail.setPatchSet(patchSet);
-    detail.setProject(project);
-
-    detail.setInfo(infoFactory.get(db, notes, patchSet.getId()));
-    detail.setPatches(patches);
-
-    final CurrentUser user = control.getUser();
-    if (user.isIdentifiedUser() && edit == null) {
-      // If we are signed in, compute the number of draft comments by the
-      // current user on each of these patch files. This way they can more
-      // quickly locate where they have pending drafts, and review them.
-      //
-      final Account.Id me = user.getAccountId();
-      for (PatchLineComment c
-          : plcUtil.draftByPatchSetAuthor(db, psIdNew, me, notes)) {
-        final Patch p = byKey.get(c.getKey().getParentKey());
-        if (p != null) {
-          p.setDraftCount(p.getDraftCount() + 1);
-        }
-      }
-
-      for (AccountPatchReview r : db.accountPatchReviews().byReviewer(me, psIdNew)) {
-        final Patch p = byKey.get(r.getKey().getPatchKey());
-        if (p != null) {
-          p.setReviewedByCurrentUser(true);
-        }
-      }
-    }
-
-    return detail;
-  }
-
-  private ObjectId toObjectId(PatchSet ps) throws NoSuchEntityException {
-    try {
-      return ObjectId.fromString(ps.getRevision().get());
-    } catch (IllegalArgumentException e) {
-      log.error("Patch set " + ps.getId() + " has invalid revision");
-      throw new NoSuchEntityException();
-    }
-  }
-
-  private PatchListKey keyFor(Whitespace whitespace) {
-    return new PatchListKey(oldId, newId, whitespace);
-  }
-
-  private PatchList listFor(PatchListKey key)
-      throws PatchListNotAvailableException {
-    return patchListCache.get(key, project);
-  }
-}
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchDetailServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchDetailServiceImpl.java
deleted file mode 100644
index d311ecc..0000000
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchDetailServiceImpl.java
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (C) 2008 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.httpd.rpc.patch;
-
-import com.google.gerrit.common.data.PatchDetailService;
-import com.google.gerrit.common.data.PatchScript;
-import com.google.gerrit.common.errors.NoSuchEntityException;
-import com.google.gerrit.extensions.client.DiffPreferencesInfo;
-import com.google.gerrit.httpd.rpc.BaseServiceImplementation;
-import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.client.Patch;
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gerrit.server.CurrentUser;
-import com.google.gerrit.server.patch.PatchScriptFactory;
-import com.google.gerrit.server.project.ChangeControl;
-import com.google.gwtjsonrpc.common.AsyncCallback;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-
-class PatchDetailServiceImpl extends BaseServiceImplementation implements
-    PatchDetailService {
-  private final PatchScriptFactory.Factory patchScriptFactoryFactory;
-  private final ChangeControl.GenericFactory changeControlFactory;
-
-  @Inject
-  PatchDetailServiceImpl(final Provider<ReviewDb> schema,
-      final Provider<CurrentUser> currentUser,
-      final PatchScriptFactory.Factory patchScriptFactoryFactory,
-      final ChangeControl.GenericFactory changeControlFactory) {
-    super(schema, currentUser);
-
-    this.patchScriptFactoryFactory = patchScriptFactoryFactory;
-    this.changeControlFactory = changeControlFactory;
-  }
-
-  @Override
-  public void patchScript(final Patch.Key patchKey, final PatchSet.Id psa,
-      final PatchSet.Id psb, final DiffPreferencesInfo dp,
-      final AsyncCallback<PatchScript> callback) {
-    if (psb == null) {
-      callback.onFailure(new NoSuchEntityException());
-      return;
-    }
-
-    new Handler<PatchScript>() {
-      @Override
-      public PatchScript call() throws Exception {
-        ChangeControl control = changeControlFactory.validateFor(
-            getDb(), patchKey.getParentKey().getParentKey(),
-            getUser());
-        return patchScriptFactoryFactory.create(
-            control, patchKey.getFileName(), psa, psb, dp).call();
-      }
-    }.to(callback);
-  }
-}
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchModule.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchModule.java
deleted file mode 100644
index 83bfcdc..0000000
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchModule.java
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (C) 2009 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.httpd.rpc.patch;
-
-import com.google.gerrit.httpd.rpc.RpcServletModule;
-import com.google.gerrit.httpd.rpc.UiRpcModule;
-
-public class PatchModule extends RpcServletModule {
-  public PatchModule() {
-    super(UiRpcModule.PREFIX);
-  }
-
-  @Override
-  protected void configureServlets() {
-    rpc(PatchDetailServiceImpl.class);
-  }
-}
diff --git a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneChangeIndex.java b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneChangeIndex.java
index 8f7e899..840f8b4 100644
--- a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneChangeIndex.java
+++ b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneChangeIndex.java
@@ -114,6 +114,7 @@
   private static final String PATCH_SET_FIELD = ChangeField.PATCH_SET.getName();
   private static final String REVIEWEDBY_FIELD =
       ChangeField.REVIEWEDBY.getName();
+  private static final String STARREDBY_FIELD = ChangeField.STARREDBY.getName();
 
   static Term idTerm(ChangeData cd) {
     return QueryBuilder.intTerm(LEGACY_ID.getName(), cd.getId().get());
@@ -413,6 +414,9 @@
     if (fields.contains(REVIEWEDBY_FIELD)) {
       decodeReviewedBy(doc, cd);
     }
+    if (fields.contains(STARREDBY_FIELD)) {
+      decodeStarredBy(doc, cd);
+    }
     return cd;
   }
 
@@ -466,6 +470,16 @@
     }
   }
 
+  private void decodeStarredBy(Document doc, ChangeData cd) {
+    IndexableField[] starredBy = doc.getFields(STARREDBY_FIELD);
+    Set<Account.Id> accounts =
+        Sets.newHashSetWithExpectedSize(starredBy.length);
+    for (IndexableField r : starredBy) {
+      accounts.add(new Account.Id(r.numericValue().intValue()));
+    }
+    cd.setStarredBy(accounts);
+  }
+
   private static <T> List<T> decodeProtos(Document doc, String fieldName,
       ProtobufCodec<T> codec) {
     BytesRef[] bytesRefs = doc.getBinaryValues(fieldName);
diff --git a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/WrappableSearcherManager.java b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/WrappableSearcherManager.java
index 7bcd0a6..7fc058c 100644
--- a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/WrappableSearcherManager.java
+++ b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/WrappableSearcherManager.java
@@ -91,7 +91,7 @@
    *
    * @throws IOException if there is a low-level I/O error
    */
-  public WrappableSearcherManager(IndexWriter writer, boolean applyAllDeletes, SearcherFactory searcherFactory) throws IOException {
+  WrappableSearcherManager(IndexWriter writer, boolean applyAllDeletes, SearcherFactory searcherFactory) throws IOException {
     if (searcherFactory == null) {
       searcherFactory = new SearcherFactory();
     }
@@ -108,7 +108,7 @@
    *
    * @throws IOException if there is a low-level I/O error
    */
-  public WrappableSearcherManager(Directory dir, SearcherFactory searcherFactory) throws IOException {
+  WrappableSearcherManager(Directory dir, SearcherFactory searcherFactory) throws IOException {
     if (searcherFactory == null) {
       searcherFactory = new SearcherFactory();
     }
@@ -127,7 +127,7 @@
    *
    * @throws IOException if there is a low-level I/O error
    */
-  public WrappableSearcherManager(DirectoryReader reader, SearcherFactory searcherFactory) throws IOException {
+  WrappableSearcherManager(DirectoryReader reader, SearcherFactory searcherFactory) throws IOException {
     if (searcherFactory == null) {
       searcherFactory = new SearcherFactory();
     }
@@ -143,7 +143,8 @@
   @Override
   protected IndexSearcher refreshIfNeeded(IndexSearcher referenceToRefresh) throws IOException {
     final IndexReader r = referenceToRefresh.getIndexReader();
-    assert r instanceof DirectoryReader: "searcher's IndexReader should be a DirectoryReader, but got " + r;
+    assert r instanceof DirectoryReader :
+      "searcher's IndexReader should be a DirectoryReader, but got " + r;
     final IndexReader newReader = DirectoryReader.openIfChanged((DirectoryReader) r);
     if (newReader == null) {
       return null;
@@ -171,7 +172,8 @@
     final IndexSearcher searcher = acquire();
     try {
       final IndexReader r = searcher.getIndexReader();
-      assert r instanceof DirectoryReader: "searcher's IndexReader should be a DirectoryReader, but got " + r;
+      assert r instanceof DirectoryReader :
+        "searcher's IndexReader should be a DirectoryReader, but got " + r;
       return ((DirectoryReader) r).isCurrent();
     } finally {
       release(searcher);
diff --git a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/DiscoveryResult.java b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/DiscoveryResult.java
index 37051da..2ee3b6b 100644
--- a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/DiscoveryResult.java
+++ b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/DiscoveryResult.java
@@ -17,7 +17,7 @@
 import java.util.Map;
 
 final class DiscoveryResult {
-  static enum Status {
+  enum Status {
     /** Provider was discovered and {@code providerUrl} is valid. */
     VALID,
 
diff --git a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/LoginForm.java b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/LoginForm.java
index 8b05c72..cb441236 100644
--- a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/LoginForm.java
+++ b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/LoginForm.java
@@ -218,7 +218,7 @@
     url.append(r.providerUrl);
     if (r.providerArgs != null && !r.providerArgs.isEmpty()) {
       boolean first = true;
-      for(Map.Entry<String, String> arg : r.providerArgs.entrySet()) {
+      for (Map.Entry<String, String> arg : r.providerArgs.entrySet()) {
         if (first) {
           url.append('?');
           first = false;
diff --git a/gerrit-patch-commonsnet/src/main/java/org/apache/commons/net/smtp/AuthSMTPClient.java b/gerrit-patch-commonsnet/src/main/java/org/apache/commons/net/smtp/AuthSMTPClient.java
index c5a9d0c..10d94d8 100644
--- a/gerrit-patch-commonsnet/src/main/java/org/apache/commons/net/smtp/AuthSMTPClient.java
+++ b/gerrit-patch-commonsnet/src/main/java/org/apache/commons/net/smtp/AuthSMTPClient.java
@@ -34,6 +34,8 @@
 
 import javax.crypto.Mac;
 import javax.crypto.spec.SecretKeySpec;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSocket;
 import javax.net.ssl.SSLSocketFactory;
 
 public class AuthSMTPClient extends SMTPClient {
@@ -55,6 +57,10 @@
 
     _socket_ = sslFactory(verify).createSocket(_socket_, hostname, port, true);
 
+    SSLParameters sslParams = new SSLParameters();
+    sslParams.setEndpointIdentificationAlgorithm("HTTPS");
+    ((SSLSocket)_socket_).setSSLParameters(sslParams);
+
     // XXX: Can't call _connectAction_() because SMTP server doesn't
     // give banner information again after STARTTLS, thus SMTP._connectAction_()
     // will wait on __getReply() forever, see source code of commons-net-2.2.
@@ -159,7 +165,7 @@
     }
 
     String cmd = encodeBase64(smtpUser.getBytes(UTF_8));
-    if(sendCommand(cmd) != 334) {
+    if (sendCommand(cmd) != 334) {
       return false;
     }
 
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java
index f57f95f..af14ff9 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java
@@ -52,7 +52,7 @@
   private boolean noAutoStart;
 
   @Option(name = "--skip-plugins", usage = "Don't install plugins")
-  private boolean skipPlugins = false;
+  private boolean skipPlugins;
 
   @Option(name = "--list-plugins", usage = "List available plugins")
   private boolean listPlugins;
@@ -60,6 +60,10 @@
   @Option(name = "--install-plugin", usage = "Install given plugin without asking")
   private List<String> installPlugins;
 
+  @Option(name = "--install-all-plugins",
+      usage = "Install all plugins from war without asking")
+  private boolean installAllPlugins;
+
   @Option(name = "--secure-store-lib",
       usage = "Path to jar providing SecureStore implementation class")
   private String secureStoreLib;
@@ -93,8 +97,14 @@
 
     if (!skipPlugins) {
       final List<PluginData> plugins =
-          InitPlugins.listPluginsAndRemoveTempFiles(init.site, pluginsDistribution);
+          InitPlugins.listPluginsAndRemoveTempFiles(init.site,
+              pluginsDistribution);
       ConsoleUI ui = ConsoleUI.getInstance(false);
+      if (installAllPlugins && !nullOrEmpty(installPlugins)) {
+        ui.message(
+            "Cannot use --install-plugin together with --install-all-plugins.\n");
+        return true;
+      }
       verifyInstallPluginList(ui, plugins);
       if (listPlugins) {
         if (!plugins.isEmpty()) {
@@ -134,6 +144,11 @@
   }
 
   @Override
+  protected boolean installAllPlugins() {
+    return installAllPlugins;
+  }
+
+  @Override
   protected ConsoleUI getConsoleUI() {
     return ConsoleUI.getInstance(batchMode);
   }
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/JythonShell.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/JythonShell.java
index d3643f3..b092784 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/JythonShell.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/JythonShell.java
@@ -134,7 +134,7 @@
       new Class[]  { String.class, pyObject },
       new Object[] { getDefaultBanner() +
         " running for Gerrit " + com.google.gerrit.common.Version.getVersion(),
-        null });
+        null, });
   }
 
   public void set(String key, Object content) {
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/LocalUsernamesToLowerCase.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/LocalUsernamesToLowerCase.java
index 224c75c..bd9ed8f 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/LocalUsernamesToLowerCase.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/LocalUsernamesToLowerCase.java
@@ -116,7 +116,7 @@
   private class Worker extends Thread {
     @Override
     public void run() {
-      try (ReviewDb db = database.open()){
+      try (ReviewDb db = database.open()) {
         for (;;) {
           final AccountExternalId extId = next();
           if (extId == null) {
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/RebuildNoteDb.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/RebuildNoteDb.java
index 7784bfe..ae4a429 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/RebuildNoteDb.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/RebuildNoteDb.java
@@ -133,8 +133,7 @@
         getChangesByProject();
     AtomicBoolean ok = new AtomicBoolean(true);
     Stopwatch sw = Stopwatch.createStarted();
-    try (Repository allUsersRepo =
-        repoManager.openMetadataRepository(allUsersName)) {
+    try (Repository allUsersRepo = repoManager.openRepository(allUsersName)) {
       deleteRefs(RefNames.REFS_DRAFT_COMMENTS, allUsersRepo);
       for (Project.NameKey project : changesByProject.keySet()) {
         try {
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Reindex.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Reindex.java
index 90c8f9f..bbb16e7 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Reindex.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Reindex.java
@@ -159,7 +159,7 @@
     int n = result.doneCount() + result.failedCount();
     double t = result.elapsed(TimeUnit.MILLISECONDS) / 1000d;
     System.out.format("Reindexed %d documents in %s index in %.01fs (%.01f/s)\n",
-        n, def.getName(), t, n/t);
+        n, def.getName(), t, n / t);
     if (result.success()) {
       index.markReady(true);
     }
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/BaseInit.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/BaseInit.java
index 2136723..d16c3bd 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/BaseInit.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/BaseInit.java
@@ -25,6 +25,7 @@
 import com.google.gerrit.common.IoUtil;
 import com.google.gerrit.pgm.init.api.ConsoleUI;
 import com.google.gerrit.pgm.init.api.InitFlags;
+import com.google.gerrit.pgm.init.api.InstallAllPlugins;
 import com.google.gerrit.pgm.init.api.InstallPlugins;
 import com.google.gerrit.pgm.init.api.LibraryDownload;
 import com.google.gerrit.pgm.util.SiteProgram;
@@ -197,6 +198,10 @@
     }
   }
 
+  protected boolean installAllPlugins() {
+    return false;
+  }
+
   protected boolean getAutoStart() {
     return false;
   }
@@ -245,6 +250,8 @@
                 getInstallPlugins(), Lists.<String> newArrayList());
         bind(new TypeLiteral<List<String>>() {}).annotatedWith(
             InstallPlugins.class).toInstance(plugins);
+        bind(new TypeLiteral<Boolean>() {}).annotatedWith(
+            InstallAllPlugins.class).toInstance(installAllPlugins());
         bind(PluginsDistribution.class).toInstance(pluginsDistribution);
 
         String secureStoreClassName;
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitDatabase.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitDatabase.java
index 0ba731a..7e4d3c1 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitDatabase.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitDatabase.java
@@ -21,7 +21,7 @@
 import com.google.gerrit.pgm.init.api.ConsoleUI;
 import com.google.gerrit.pgm.init.api.InitStep;
 import com.google.gerrit.pgm.init.api.Section;
-import com.google.gerrit.server.api.config.GerritServerIdProvider;
+import com.google.gerrit.server.config.GerritServerIdProvider;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.inject.Binding;
 import com.google.inject.Guice;
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitIndex.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitIndex.java
index 0883ac6..28b7b17 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitIndex.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitIndex.java
@@ -64,6 +64,7 @@
           site, def.getLatest().getVersion(), true);
     }
     if ((site.isNew || isEmptySite()) && type == IndexType.LUCENE) {
+      // Do nothing
     } else {
       final String message = String.format(
         "\nThe index must be %sbuilt before starting Gerrit:\n"
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitPlugins.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitPlugins.java
index 7fdd7e2..c9b2b92 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitPlugins.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitPlugins.java
@@ -68,10 +68,11 @@
       }
     });
     return FluentIterable.from(result).toSortedList(new Comparator<PluginData>() {
-      @Override
-      public int compare(PluginData a, PluginData b) {
-        return a.name.compareTo(b.name);
-      }});
+        @Override
+        public int compare(PluginData a, PluginData b) {
+          return a.name.compareTo(b.name);
+        }
+      });
   }
 
   private final ConsoleUI ui;
@@ -121,17 +122,18 @@
         Path p = site.plugins_dir.resolve(plugin.name + ".jar");
         boolean upgrade = Files.exists(p);
 
-        if (!(initFlags.installPlugins.contains(pluginName) || ui.yesno(upgrade,
-            "Install plugin %s version %s", pluginName, plugin.version))) {
+        if (!(initFlags.installPlugins.contains(pluginName)
+            || initFlags.installAllPlugins
+            || ui.yesno(upgrade, "Install plugin %s version %s", pluginName,
+                plugin.version))) {
           Files.deleteIfExists(tmpPlugin);
           continue;
         }
 
         if (upgrade) {
           final String installedPluginVersion = getVersion(p);
-          if (!ui.yesno(upgrade,
-              "version %s is already installed, overwrite it",
-              installedPluginVersion)) {
+          if (!ui.yesno(upgrade, "%s %s is already installed, overwrite it",
+              plugin.name, installedPluginVersion)) {
             Files.deleteIfExists(tmpPlugin);
             continue;
           }
@@ -144,6 +146,12 @@
         }
         try {
           Files.move(tmpPlugin, p);
+          if (upgrade) {
+            // or update that is not an upgrade
+            ui.message("Updated %s to %s\n", plugin.name, plugin.version);
+          } else {
+            ui.message("Installed %s %s\n", plugin.name, plugin.version);
+          }
         } catch (IOException e) {
           throw new IOException("Failed to install plugin " + pluginName
               + ": " + tmpPlugin.toAbsolutePath() + " -> "
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitSshd.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitSshd.java
index bdebd6c..cb4439a 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitSshd.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitSshd.java
@@ -105,22 +105,22 @@
 
         System.err.print(" rsa...");
         System.err.flush();
-        Runtime.getRuntime().exec(new String[] {"ssh-keygen", //
-            "-q" /* quiet */, //
-            "-t", "rsa", //
-            "-P", "", //
-            "-C", comment, //
-            "-f", site.ssh_rsa.toAbsolutePath().toString() //
+        Runtime.getRuntime().exec(new String[] {"ssh-keygen",
+            "-q" /* quiet */,
+            "-t", "rsa",
+            "-P", "",
+            "-C", comment,
+            "-f", site.ssh_rsa.toAbsolutePath().toString(),
             }).waitFor();
 
         System.err.print(" dsa...");
         System.err.flush();
-        Runtime.getRuntime().exec(new String[] {"ssh-keygen", //
-            "-q" /* quiet */, //
-            "-t", "dsa", //
-            "-P", "", //
-            "-C", comment, //
-            "-f", site.ssh_dsa.toAbsolutePath().toString() //
+        Runtime.getRuntime().exec(new String[] {"ssh-keygen",
+            "-q" /* quiet */,
+            "-t", "dsa",
+            "-P", "",
+            "-C", comment,
+            "-f", site.ssh_dsa.toAbsolutePath().toString(),
             }).waitFor();
 
       } else {
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/Libraries.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/Libraries.java
index 282e75a..b4c672a 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/Libraries.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/Libraries.java
@@ -116,7 +116,7 @@
     return doGet(cfg, name, key, true);
   }
 
-  private static final String doGet(Config cfg, String name, String key,
+  private static String doGet(Config cfg, String name, String key,
       boolean required) {
     String val = cfg.getString("library", name, key);
     if ((val == null || val.isEmpty()) && required) {
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/AllProjectsConfig.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/AllProjectsConfig.java
index cb58c6e..f7d9d4a 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/AllProjectsConfig.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/AllProjectsConfig.java
@@ -180,7 +180,7 @@
     ru.setExpectedOldObjectId(revision);
     ru.setRefLogMessage(refLogMsg, false);
     RefUpdate.Result r = ru.update();
-    switch(r) {
+    switch (r) {
       case FAST_FORWARD:
       case NEW:
       case NO_CHANGE:
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/InitFlags.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/InitFlags.java
index bdd8b86..f0674d6 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/InitFlags.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/InitFlags.java
@@ -45,17 +45,19 @@
   public final FileBasedConfig cfg;
   public final SecureStore sec;
   public final List<String> installPlugins;
+  public final boolean installAllPlugins;
 
   @VisibleForTesting
   @Inject
   public InitFlags(final SitePaths site,
       final SecureStore secureStore,
-      @InstallPlugins final List<String> installPlugins) throws IOException,
-      ConfigInvalidException {
+      @InstallPlugins final List<String> installPlugins,
+      @InstallAllPlugins final Boolean installAllPlugins) throws IOException,
+          ConfigInvalidException {
     sec = secureStore;
     this.installPlugins = installPlugins;
+    this.installAllPlugins = installAllPlugins;
     cfg = new FileBasedConfig(site.gerrit_config.toFile(), FS.DETECTED);
-
     cfg.load();
   }
 }
diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrettyFactory.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/InstallAllPlugins.java
similarity index 63%
copy from gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrettyFactory.java
copy to gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/InstallAllPlugins.java
index f68b629..809a197 100644
--- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrettyFactory.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/api/InstallAllPlugins.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2010 The Android Open Source Project
+// Copyright (C) 2016 The Android Open Source Project
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -12,9 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.prettify.client;
+package com.google.gerrit.pgm.init.api;
 
-/** Creates a new PrettyFormatter instance for one formatting run. */
-public interface PrettyFactory {
-  PrettyFormatter get();
+import com.google.inject.BindingAnnotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@BindingAnnotation
+@Retention(RetentionPolicy.RUNTIME)
+public @interface InstallAllPlugins {
 }
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/rules/PrologCompiler.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/rules/PrologCompiler.java
index 064cc19..8d3c766 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/rules/PrologCompiler.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/rules/PrologCompiler.java
@@ -66,7 +66,7 @@
     PrologCompiler create(Repository git);
   }
 
-  public static enum Status {
+  public enum Status {
     NO_RULES, COMPILED
   }
 
diff --git a/gerrit-pgm/src/main/resources/com/google/gerrit/pgm/init/libraries.config b/gerrit-pgm/src/main/resources/com/google/gerrit/pgm/init/libraries.config
index 39d647d..4a1e587 100644
--- a/gerrit-pgm/src/main/resources/com/google/gerrit/pgm/init/libraries.config
+++ b/gerrit-pgm/src/main/resources/com/google/gerrit/pgm/init/libraries.config
@@ -16,14 +16,14 @@
 # Version should match lib/bouncycastle/BUCK
 [library "bouncyCastleProvider"]
   name = Bouncy Castle Crypto Provider v152
-  url = http://www.bouncycastle.org/download/bcprov-jdk15on-152.jar
+  url = http://repo2.maven.org/maven2/org/bouncycastle/bcprov-jdk15on/1.52/bcprov-jdk15on-1.52.jar
   sha1 = 88a941faf9819d371e3174b5ed56a3f3f7d73269
   remove = bcprov-.*[.]jar
 
 # Version should match lib/bouncycastle/BUCK
 [library "bouncyCastleSSL"]
   name = Bouncy Castle Crypto SSL v152
-  url = http://www.bouncycastle.org/download/bcpkix-jdk15on-152.jar
+  url = http://repo2.maven.org/maven2/org/bouncycastle/bcpkix-jdk15on/1.52/bcpkix-jdk15on-1.52.jar
   sha1 = b8ffac2bbc6626f86909589c8cc63637cc936504
   needs = bouncyCastleProvider
   remove = bcpkix-.*[.]jar
@@ -31,7 +31,7 @@
 # Version should match lib/bouncycastle/BUCK
 [library "bouncyCastlePGP"]
   name = Bouncy Castle Crypto OpenPGP v152
-  url = http://www.bouncycastle.org/download/bcpg-jdk15on-152.jar
+  url = http://repo2.maven.org/maven2/org/bouncycastle/bcpg-jdk15on/1.52/bcpg-jdk15on-1.52.jar
   sha1 = ff4665a4b5633ff6894209d5dd10b7e612291858
   needs = bouncyCastleProvider
   remove = bcpg-.*[.]jar
diff --git a/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/UpgradeFrom2_0_xTest.java b/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/UpgradeFrom2_0_xTest.java
index dc7ce59..af30f73 100644
--- a/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/UpgradeFrom2_0_xTest.java
+++ b/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/UpgradeFrom2_0_xTest.java
@@ -71,8 +71,8 @@
     old.save();
 
     final InMemorySecureStore secureStore = new InMemorySecureStore();
-    final InitFlags flags =
-        new InitFlags(site, secureStore, Collections.<String> emptyList());
+    final InitFlags flags = new InitFlags(site, secureStore,
+        Collections.<String> emptyList(), false);
     final ConsoleUI ui = createStrictMock(ConsoleUI.class);
     Section.Factory sections = new Section.Factory() {
       @Override
diff --git a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/BUCK b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/BUCK
index b224bf6..f33929d 100644
--- a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/BUCK
+++ b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/BUCK
@@ -10,7 +10,6 @@
     'Gerrit-ApiType: plugin',
     'Gerrit-ApiVersion: ${gerritApiVersion}',
     'Gerrit-Module: ${package}.Module',
-    'Gerrit-HttpModule: ${package}.HttpModule',
   ],
 )
 
diff --git a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/HttpModule.java b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/HttpModule.java
deleted file mode 100644
index 4f043d0..0000000
--- a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/HttpModule.java
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package ${package};
-
-import com.google.gerrit.extensions.registration.DynamicSet;
-import com.google.gerrit.extensions.webui.GwtPlugin;
-import com.google.gerrit.extensions.webui.WebUiPlugin;
-import com.google.gerrit.httpd.plugins.HttpPluginModule;
-
-public class HttpModule extends HttpPluginModule {
-
-  @Override
-  protected void configureServlets() {
-    DynamicSet.bind(binder(), WebUiPlugin.class)
-        .toInstance(new GwtPlugin("hello_gwt_plugin"));
-  }
-}
diff --git a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/Module.java b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/Module.java
index c734bb7..73e5695 100644
--- a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/Module.java
+++ b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/Module.java
@@ -15,7 +15,9 @@
 package ${package};
 
 import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.extensions.webui.GwtPlugin;
 import com.google.gerrit.extensions.webui.TopMenu;
+import com.google.gerrit.extensions.webui.WebUiPlugin;
 import com.google.inject.AbstractModule;
 
 public class Module extends AbstractModule {
@@ -23,5 +25,7 @@
   @Override
   protected void configure() {
     DynamicSet.bind(binder(), TopMenu.class).to(HelloMenu.class);
+    DynamicSet.bind(binder(), WebUiPlugin.class)
+        .toInstance(new GwtPlugin("hello_gwt_plugin"));
   }
 }
diff --git a/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/Plugin.java b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/Plugin.java
index f4f427b..14e3155 100644
--- a/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/Plugin.java
+++ b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/Plugin.java
@@ -39,48 +39,48 @@
   }
 
   /** Installed name of the plugin. */
-  public final String getName() {
+  public String getName() {
     return getPluginName();
   }
 
   /** Installed name of the plugin. */
-  public final native String getPluginName()
+  public native String getPluginName()
   /*-{ return this.getPluginName() }-*/;
 
   /** Navigate the UI to the screen identified by the token. */
-  public final native void go(String token)
+  public native void go(String token)
   /*-{ return this.go(token) }-*/;
 
   /** Refresh the current UI. */
-  public final native void refresh()
+  public native void refresh()
   /*-{ return this.refresh() }-*/;
 
   /** Refresh Gerrit's menu bar. */
-  public final native void refreshMenuBar()
+  public native void refreshMenuBar()
   /*-{ return this.refreshMenuBar() }-*/;
 
   /** @return the preferences of the currently signed in user, the default preferences if not signed in */
-  public final native GeneralPreferences getUserPreferences()
+  public native GeneralPreferences getUserPreferences()
   /*-{ return this.getUserPreferences() }-*/;
 
   /** Refresh the user preferences of the current user. */
-  public final native void refreshUserPreferences()
+  public native void refreshUserPreferences()
   /*-{ return this.refreshUserPreferences() }-*/;
 
   /** @return the server info */
-  public final native ServerInfo getServerInfo()
+  public native ServerInfo getServerInfo()
   /*-{ return this.getServerInfo() }-*/;
 
   /** @return the current user */
-  public final native AccountInfo getCurrentUser()
+  public native AccountInfo getCurrentUser()
   /*-{ return this.getCurrentUser() }-*/;
 
   /** Check if user is signed in. */
-  public final native boolean isSignedIn()
+  public native boolean isSignedIn()
   /*-{ return this.isSignedIn() }-*/;
 
   /** Show message in Gerrit's ErrorDialog. */
-  public final native void showError(String message)
+  public native void showError(String message)
   /*-{ return this.showError(message) }-*/;
 
   /**
@@ -90,11 +90,11 @@
    *        regular expression matching use {@code screenRegex()} .
    * @param entry callback function invoked to create the screen widgets.
    */
-  public final void screen(String token, Screen.EntryPoint entry) {
+  public void screen(String token, Screen.EntryPoint entry) {
     screen(token, wrap(entry));
   }
 
-  private final native void screen(String t, JavaScriptObject e)
+  private native void screen(String t, JavaScriptObject e)
   /*-{ this.screen(t, e) }-*/;
 
   /**
@@ -105,11 +105,11 @@
    *        {@code Screen} object passed into the {@code Screen.EntryPoint}.
    * @param entry callback function invoked to create the screen widgets.
    */
-  public final void screenRegex(String regex, Screen.EntryPoint entry) {
+  public void screenRegex(String regex, Screen.EntryPoint entry) {
     screenRegex(regex, wrap(entry));
   }
 
-  private final native void screenRegex(String p, JavaScriptObject e)
+  private native void screenRegex(String p, JavaScriptObject e)
   /*-{ this.screen(new $wnd.RegExp(p), e) }-*/;
 
   /**
@@ -118,11 +118,11 @@
    * @param token literal anchor token appearing after the plugin name.
    * @param entry callback function invoked to create the settings screen widgets.
    */
-  public final void settingsScreen(String token, String menu, Screen.EntryPoint entry) {
+  public void settingsScreen(String token, String menu, Screen.EntryPoint entry) {
     settingsScreen(token, menu, wrap(entry));
   }
 
-  private final native void settingsScreen(String t, String m, JavaScriptObject e)
+  private native void settingsScreen(String t, String m, JavaScriptObject e)
   /*-{ this.settingsScreen(t, m, e) }-*/;
 
   /**
@@ -132,11 +132,11 @@
    *        registered.
    * @param entry callback function invoked to create the panel widgets.
    */
-  public final void panel(GerritUiExtensionPoint extensionPoint, Panel.EntryPoint entry) {
+  public void panel(GerritUiExtensionPoint extensionPoint, Panel.EntryPoint entry) {
     panel(extensionPoint.name(), wrap(entry));
   }
 
-  private final native void panel(String i, JavaScriptObject e)
+  private native void panel(String i, JavaScriptObject e)
   /*-{ this.panel(i, e) }-*/;
 
   protected Plugin() {
@@ -144,17 +144,17 @@
 
   native void _initialized() /*-{ this._success = true }-*/;
   native void _loaded() /*-{ this._loadedGwt() }-*/;
-  private static final native Plugin install(String u)
+  private static native Plugin install(String u)
   /*-{ return $wnd.Gerrit.installGwt(u) }-*/;
 
-  private static final native JavaScriptObject wrap(Screen.EntryPoint b) /*-{
+  private static native JavaScriptObject wrap(Screen.EntryPoint b) /*-{
     return $entry(function(c){
       b.@com.google.gerrit.plugin.client.screen.Screen.EntryPoint::onLoad(Lcom/google/gerrit/plugin/client/screen/Screen;)(
         @com.google.gerrit.plugin.client.screen.Screen::new(Lcom/google/gerrit/plugin/client/screen/Screen$Context;)(c));
     });
   }-*/;
 
-  private static final native JavaScriptObject wrap(Panel.EntryPoint b) /*-{
+  private static native JavaScriptObject wrap(Panel.EntryPoint b) /*-{
     return $entry(function(c){
       b.@com.google.gerrit.plugin.client.extension.Panel.EntryPoint::onLoad(Lcom/google/gerrit/plugin/client/extension/Panel;)(
         @com.google.gerrit.plugin.client.extension.Panel::new(Lcom/google/gerrit/plugin/client/extension/Panel$Context;)(c));
diff --git a/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/extension/Panel.java b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/extension/Panel.java
index 1fff691..0200a14 100644
--- a/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/extension/Panel.java
+++ b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/extension/Panel.java
@@ -60,20 +60,20 @@
   }
 
   static final class Context extends JavaScriptObject {
-    final native Element body() /*-{ return this.body }-*/;
+    native Element body() /*-{ return this.body }-*/;
 
-    final native String get(String k) /*-{ return this.p[k]; }-*/;
-    final native int getInt(String k, int d) /*-{
+    native String get(String k) /*-{ return this.p[k]; }-*/;
+    native int getInt(String k, int d) /*-{
       return this.p.hasOwnProperty(k) ? this.p[k] : d
     }-*/;
-    final native int getBoolean(String k, boolean d) /*-{
+    native int getBoolean(String k, boolean d) /*-{
       return this.p.hasOwnProperty(k) ? this.p[k] : d
     }-*/;
-    final native JavaScriptObject getObject(String k)
+    native JavaScriptObject getObject(String k)
     /*-{ return this.p[k]; }-*/;
 
 
-    final native void detach(Panel p) /*-{
+    native void detach(Panel p) /*-{
       this.onUnload($entry(function(){
         p.@com.google.gwt.user.client.ui.Widget::onDetach()();
       }));
diff --git a/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/screen/Screen.java b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/screen/Screen.java
index f91464f..5e0ba4a 100644
--- a/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/screen/Screen.java
+++ b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/screen/Screen.java
@@ -62,12 +62,12 @@
   }
 
   static final class Context extends JavaScriptObject {
-    final native Element body() /*-{ return this.body }-*/;
-    final native JsArrayString token_match() /*-{ return this.token_match }-*/;
-    final native void show() /*-{ this.show() }-*/;
-    final native void setTitle(String t) /*-{ this.setTitle(t) }-*/;
-    final native void setWindowTitle(String t) /*-{ this.setWindowTitle(t) }-*/;
-    final native void detach(Screen s) /*-{
+    native Element body() /*-{ return this.body }-*/;
+    native JsArrayString token_match() /*-{ return this.token_match }-*/;
+    native void show() /*-{ this.show() }-*/;
+    native void setTitle(String t) /*-{ this.setTitle(t) }-*/;
+    native void setWindowTitle(String t) /*-{ this.setWindowTitle(t) }-*/;
+    native void detach(Screen s) /*-{
       this.onUnload($entry(function(){
         s.@com.google.gwt.user.client.ui.Widget::onDetach()();
       }));
@@ -87,7 +87,7 @@
   }
 
   /** @return the token suffix after {@code "/#/x/plugin-name/"}. */
-  public final String getToken() {
+  public String getToken() {
     return getToken(0);
   }
 
@@ -96,12 +96,12 @@
    *        group 0 is the entire token, see {@link #getToken()}.
    * @return the token from the regex match group.
    */
-  public final String getToken(int group) {
+  public String getToken(int group) {
     return ctx.token_match().get(group);
   }
 
   /** @return total number of token groups. */
-  public final int getTokenGroups() {
+  public int getTokenGroups() {
     return ctx.token_match().length();
   }
 
@@ -110,7 +110,7 @@
    *
    * @param titleText text to display above the widget.
    */
-  public final void setPageTitle(String titleText) {
+  public void setPageTitle(String titleText) {
     ctx.setTitle(titleText);
   }
 
@@ -119,7 +119,7 @@
    *
    * @param titleText text to display in the window title bar.
    */
-  public final void setWindowTitle(String titleText) {
+  public void setWindowTitle(String titleText) {
     ctx.setWindowTitle(titleText);
   }
 
@@ -128,13 +128,13 @@
    *
    * @param w child containing the content.
    */
-  public final void show(Widget w) {
+  public void show(Widget w) {
     setWidget(w);
     ctx.show();
   }
 
   /** Show this screen in the web interface. */
-  public final void show() {
+  public void show() {
     ctx.show();
   }
 }
diff --git a/gerrit-prettify/BUCK b/gerrit-prettify/BUCK
index baaf56d..37f08a0 100644
--- a/gerrit-prettify/BUCK
+++ b/gerrit-prettify/BUCK
@@ -3,15 +3,10 @@
 gwt_module(
   name = 'client',
   srcs = glob([
-    SRC + 'client/**/*.java',
     SRC + 'common/**/*.java',
   ]),
   gwt_xml = SRC + 'PrettyFormatter.gwt.xml',
-  resources = glob([
-    'src/main/java/com/google/gerrit/prettify/client/*.properties',
-  ]),
   deps = [
-    ':google-code-prettify',
     '//gerrit-gwtexpui:SafeHtml',
   ],
   exported_deps = [
@@ -27,16 +22,6 @@
 )
 
 java_library(
-  name = 'google-code-prettify',
-  resources = glob([
-    'src/main/resources/com/google/gerrit/prettify/client/**/*',
-  ]),
-  deps = [
-    '//lib:LICENSE-Apache2.0',
-  ],
-)
-
-java_library(
   name = 'server',
   srcs = glob([SRC + 'common/**/*.java']),
   deps = [
diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/PrettyFormatter.gwt.xml b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/PrettyFormatter.gwt.xml
index fd88f6c..06035d27 100644
--- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/PrettyFormatter.gwt.xml
+++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/PrettyFormatter.gwt.xml
@@ -24,5 +24,4 @@
   <inherits name='com.google.gwt.resources.Resources'/>
   <inherits name='com.google.gwtexpui.safehtml.SafeHtml'/>
   <source path='common' />
-  <source path='client' />
 </module>
diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/ClientSideFormatter.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/ClientSideFormatter.java
deleted file mode 100644
index 34ddde2..0000000
--- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/ClientSideFormatter.java
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright (C) 2010 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.prettify.client;
-
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.core.client.JavaScriptObject;
-import com.google.gwt.user.client.ui.RootPanel;
-
-/** Evaluates prettify using the host browser's JavaScript engine. */
-public class ClientSideFormatter extends PrettyFormatter {
-  public static final PrettyFactory FACTORY = new PrettyFactory() {
-    @Override
-    public PrettyFormatter get() {
-      return new ClientSideFormatter();
-    }
-  };
-
-  private static final PrivateScopeImpl prettify;
-
-  static {
-    Resources.I.prettify_css().ensureInjected();
-    Resources.I.gerrit_css().ensureInjected();
-
-    prettify = GWT.create(PrivateScopeImpl.class);
-    RootPanel.get().add(prettify);
-
-    prettify.compile(Resources.I.core());
-    prettify.compile(Resources.I.lang_apollo());
-    prettify.compile(Resources.I.lang_basic());
-    prettify.compile(Resources.I.lang_clj());
-    prettify.compile(Resources.I.lang_css());
-    prettify.compile(Resources.I.lang_dart());
-    prettify.compile(Resources.I.lang_erlang());
-    prettify.compile(Resources.I.lang_go());
-    prettify.compile(Resources.I.lang_hs());
-    prettify.compile(Resources.I.lang_lisp());
-    prettify.compile(Resources.I.lang_llvm());
-    prettify.compile(Resources.I.lang_lua());
-    prettify.compile(Resources.I.lang_matlab());
-    prettify.compile(Resources.I.lang_ml());
-    prettify.compile(Resources.I.lang_mumps());
-    prettify.compile(Resources.I.lang_n());
-    prettify.compile(Resources.I.lang_pascal());
-    prettify.compile(Resources.I.lang_proto());
-    prettify.compile(Resources.I.lang_r());
-    prettify.compile(Resources.I.lang_rd());
-    prettify.compile(Resources.I.lang_scala());
-    prettify.compile(Resources.I.lang_sql());
-    prettify.compile(Resources.I.lang_tcl());
-    prettify.compile(Resources.I.lang_tex());
-    prettify.compile(Resources.I.lang_vb());
-    prettify.compile(Resources.I.lang_vhdl());
-    prettify.compile(Resources.I.lang_wiki());
-    prettify.compile(Resources.I.lang_xq());
-    prettify.compile(Resources.I.lang_yaml());
-  }
-
-  @Override
-  protected String prettify(String html, String type) {
-    return go(prettify.getContext(), html, type);
-  }
-
-  private static native String go(JavaScriptObject ctx, String srcText,
-      String srcType)
-  /*-{
-     return ctx.prettyPrintOne(srcText, srcType);
-  }-*/;
-}
diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrettifyConstants.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrettifyConstants.java
deleted file mode 100644
index c191fa5..0000000
--- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrettifyConstants.java
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (C) 2010 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.prettify.client;
-
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.i18n.client.Constants;
-
-public interface PrettifyConstants extends Constants {
-  static final PrettifyConstants C = GWT.create(PrettifyConstants.class);
-
-  String wseTabAfterSpace();
-  String wseTrailingSpace();
-  String wseBareCR();
-  String leCR();
-}
diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrettifyConstants.properties b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrettifyConstants.properties
deleted file mode 100644
index 97ab0cf..0000000
--- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrettifyConstants.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-wseTabAfterSpace=Whitespace error: Tab after space
-wseTrailingSpace=Whitespace error: Trailing space at end of line
-wseBareCR=CR without LF
-leCR=Carriage Return
diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrettyFormatter.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrettyFormatter.java
deleted file mode 100644
index 49dc2fc..0000000
--- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrettyFormatter.java
+++ /dev/null
@@ -1,561 +0,0 @@
-// Copyright (C) 2010 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.prettify.client;
-
-import com.google.gerrit.extensions.client.DiffPreferencesInfo;
-import com.google.gerrit.prettify.common.SparseFileContent;
-import com.google.gwtexpui.safehtml.client.SafeHtml;
-import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
-
-import org.eclipse.jgit.diff.Edit;
-import org.eclipse.jgit.diff.ReplaceEdit;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-public abstract class PrettyFormatter implements SparseHtmlFile {
-  public abstract static class EditFilter {
-    abstract String getStyleName();
-
-    abstract int getBegin(Edit edit);
-
-    abstract int getEnd(Edit edit);
-  }
-
-  public static final EditFilter A = new EditFilter() {
-    @Override
-    String getStyleName() {
-      return "wdd";
-    }
-
-    @Override
-    int getBegin(Edit edit) {
-      return edit.getBeginA();
-    }
-
-    @Override
-    int getEnd(Edit edit) {
-      return edit.getEndA();
-    }
-  };
-
-  public static final EditFilter B = new EditFilter() {
-    @Override
-    String getStyleName() {
-      return "wdi";
-    }
-
-    @Override
-    int getBegin(Edit edit) {
-      return edit.getBeginB();
-    }
-
-    @Override
-    int getEnd(Edit edit) {
-      return edit.getEndB();
-    }
-  };
-
-  protected SparseFileContent content;
-  protected EditFilter side;
-  protected List<Edit> edits;
-  protected DiffPreferencesInfo diffPrefs;
-  protected String fileName;
-  protected Set<Integer> trailingEdits;
-
-  private int col;
-  private int lineIdx;
-  private Tag lastTag;
-  private StringBuilder buf;
-
-  @Override
-  public SafeHtml getSafeHtmlLine(int lineNo) {
-    return SafeHtml.asis(content.get(lineNo));
-  }
-
-  @Override
-  public int size() {
-    return content.size();
-  }
-
-  @Override
-  public boolean contains(int idx) {
-    return content.contains(idx);
-  }
-
-  @Override
-  public boolean hasTrailingEdit(int idx) {
-    return trailingEdits.contains(idx);
-  }
-
-  public void setEditFilter(EditFilter f) {
-    side = f;
-  }
-
-  public void setEditList(List<Edit> all) {
-    edits = all;
-  }
-
-  public void setDiffPrefs(DiffPreferencesInfo how) {
-    diffPrefs = how;
-  }
-
-  public void setFileName(String fileName) {
-    this.fileName = fileName;
-  }
-
-  /**
-   * Parse and format a complete source code file.
-   *
-   * @param src raw content of the file to format. The line strings will be HTML
-   *        escaped before processing, so it must be the raw text.
-   */
-  public void format(SparseFileContent src) {
-    content = new SparseFileContent();
-    content.setSize(src.size());
-    trailingEdits = new HashSet<>();
-
-    String html = toHTML(src);
-
-    html = expandTabs(html);
-    if (diffPrefs.syntaxHighlighting && getFileType() != null
-        && src.isWholeFile()) {
-      // The prettify parsers don't like &#39; as an entity for the
-      // single quote character. Replace them all out so we don't
-      // confuse the parser.
-      //
-      html = html.replaceAll("&#39;", "'");
-
-      // If a line is modified at its end and the line ending is changed from
-      // '\n' to '\r\n' then the '\r' of the new line is part of the modified
-      // text. If intraline diffs are highlighted the modified text is
-      // surrounded by a 'span' tag. As result '\r' and '\n' of the new line get
-      // separated by '</span>'. For the prettify parser this now looks like two
-      // separate line endings. This messes up the line counting below.
-      // Drop any '\r' to avoid this problem.
-      html = html.replaceAll("\r</span>(<span class=\"wdc\">)?\n", "</span>$1\n");
-
-      html = html.replaceAll("(\r)?\n", " $1\n");
-      html = prettify(html, getFileType());
-      html = html.replaceAll(" (\r)?\n", "$1\n");
-    }
-
-    int pos = 0;
-    int textChunkStart = 0;
-
-    lastTag = Tag.NULL;
-    col = 0;
-    lineIdx = 0;
-
-    buf = new StringBuilder();
-    while (pos <= html.length()) {
-      int tagStart = html.indexOf('<', pos);
-      int lf = html.indexOf('\n', pos);
-
-      if (tagStart < 0 && lf < 0) {
-        // No more tags remaining. What's left is plain text.
-        //
-        assert lastTag == Tag.NULL;
-        pos = html.length();
-        if (textChunkStart < pos) {
-          htmlText(html.substring(textChunkStart, pos));
-        }
-        if (0 < buf.length()) {
-          content.addLine(src.mapIndexToLine(lineIdx), buf.toString());
-        }
-        break;
-      }
-
-      // Line end occurs before the next HTML tag. Break the line.
-      if (0 <= lf && (lf < tagStart || tagStart < 0)) {
-        if (textChunkStart < lf) {
-          lastTag.open(buf, html);
-          htmlText(html.substring(textChunkStart, lf));
-        }
-        pos = lf + 1;
-        textChunkStart = pos;
-
-        lastTag.close(buf, html);
-        content.addLine(src.mapIndexToLine(lineIdx++), buf.toString());
-        buf = new StringBuilder();
-        col = 0;
-        continue;
-      }
-
-      // Assume no attribute contains '>' and that all tags
-      // within the HTML will be well-formed.
-      //
-      int tagEnd = html.indexOf('>', tagStart);
-      assert tagStart < tagEnd;
-      pos = tagEnd + 1;
-
-      // Handle any text between the end of the last tag,
-      // and the start of this tag.
-      //
-      if (textChunkStart < tagStart) {
-        lastTag.open(buf, html);
-        htmlText(html.substring(textChunkStart, tagStart));
-      }
-      textChunkStart = pos;
-
-      if (html.charAt(tagStart + 1) == '/') {
-        lastTag = lastTag.pop(buf, html);
-
-      } else if (html.charAt(tagEnd - 1) != '/') {
-        lastTag = new Tag(lastTag, tagStart, tagEnd);
-      }
-    }
-    buf = null;
-  }
-
-  private void htmlText(String txt) {
-    int pos = 0;
-    while (pos < txt.length()) {
-      int start = txt.indexOf('&', pos);
-      if (start < 0) {
-        break;
-      }
-
-      cleanText(txt, pos, start);
-      pos = txt.indexOf(';', start + 1) + 1;
-
-      if (diffPrefs.lineLength <= col) {
-        buf.append("<br />");
-        col = 0;
-      }
-
-      buf.append(txt.substring(start, pos));
-      col++;
-    }
-
-    cleanText(txt, pos, txt.length());
-  }
-
-  private void cleanText(String txt, int pos, int end) {
-    while (pos < end) {
-      int free = diffPrefs.lineLength - col;
-      if (free <= 0) {
-        // The current line is full. Throw an explicit line break
-        // onto the end, and we'll continue on the next line.
-        //
-        buf.append("<br />");
-        col = 0;
-        free = diffPrefs.lineLength;
-      }
-
-      int n = Math.min(end - pos, free);
-      buf.append(txt.substring(pos, pos + n));
-      col += n;
-      pos += n;
-    }
-  }
-
-  /** Run the prettify engine over the text and return the result. */
-  protected abstract String prettify(String html, String type);
-
-  private static class Tag {
-    static final Tag NULL = new Tag(null, 0, 0) {
-      @Override
-      void open(StringBuilder buf, String html) {
-      }
-
-      @Override
-      void close(StringBuilder buf, String html) {
-      }
-
-      @Override
-      Tag pop(StringBuilder buf, String html) {
-        return this;
-      }
-    };
-
-    final Tag parent;
-    final int start;
-    final int end;
-    boolean open;
-
-    Tag(Tag p, int s, int e) {
-      parent = p;
-      start = s;
-      end = e;
-    }
-
-    void open(StringBuilder buf, String html) {
-      if (!open) {
-        parent.open(buf, html);
-        buf.append(html.substring(start, end + 1));
-        open = true;
-      }
-    }
-
-    void close(StringBuilder buf, String html) {
-      pop(buf, html);
-      parent.close(buf, html);
-    }
-
-    Tag pop(StringBuilder buf, String html) {
-      if (open) {
-        int sp = html.indexOf(' ', start + 1);
-        if (sp < 0 || end < sp) {
-          sp = end;
-        }
-
-        buf.append("</");
-        buf.append(html.substring(start + 1, sp));
-        buf.append('>');
-        open = false;
-      }
-      return parent;
-    }
-  }
-
-  private String toHTML(SparseFileContent src) {
-    SafeHtml html;
-
-    if (diffPrefs.intralineDifference) {
-      html = colorLineEdits(src);
-    } else {
-      SafeHtmlBuilder b = new SafeHtmlBuilder();
-      for (int index = src.first(); index < src.size(); index = src.next(index)) {
-        b.append(src.get(index));
-        b.append('\n');
-      }
-      html = b;
-
-      final String r = "<span class=\"wse\"" //
-          + " title=\"" + PrettifyConstants.C.wseBareCR() + "\"" //
-          + ">&nbsp;</span>$1";
-      html = html.replaceAll("\r([^\n])", r);
-    }
-
-    if (diffPrefs.showWhitespaceErrors) {
-      // We need to do whitespace errors before showing tabs, because
-      // these patterns rely on \t as a literal, before it expands.
-      //
-      html = showTabAfterSpace(html);
-      html = showTrailingWhitespace(html);
-    }
-
-    if (diffPrefs.showLineEndings){
-      html = showLineEndings(html);
-    }
-
-    if (diffPrefs.showTabs) {
-      String t = 1 < diffPrefs.tabSize ? "\t" : "";
-      html = html.replaceAll("\t", "<span class=\"vt\">\u00BB</span>" + t);
-    }
-
-    return html.asString();
-  }
-
-  private SafeHtml colorLineEdits(SparseFileContent src) {
-    // Make a copy of the edits with a sentinel that is after all lines
-    // in the source. That simplifies our loop below because we'll never
-    // run off the end of the edit list.
-    //
-    List<Edit> edits = new ArrayList<>(this.edits.size() + 1);
-    edits.addAll(this.edits);
-    edits.add(new Edit(src.size(), src.size()));
-
-    SafeHtmlBuilder buf = new SafeHtmlBuilder();
-
-    int curIdx = 0;
-    Edit curEdit = edits.get(curIdx);
-
-    ReplaceEdit lastReplace = null;
-    List<Edit> charEdits = null;
-    int lastPos = 0;
-    int lastIdx = 0;
-
-    for (int index = src.first(); index < src.size(); index = src.next(index)) {
-      int cmp = compare(index, curEdit);
-      while (0 < cmp) {
-        // The index is after the edit. Skip to the next edit.
-        //
-        curEdit = edits.get(curIdx++);
-        cmp = compare(index, curEdit);
-      }
-
-      if (cmp < 0) {
-        // index occurs before the edit. This is a line of context.
-        //
-        appendShowBareCR(buf, src.get(index), true);
-        buf.append('\n');
-        continue;
-      }
-
-      // index occurs within the edit. The line is a modification.
-      //
-      if (curEdit instanceof ReplaceEdit) {
-        if (lastReplace != curEdit) {
-          lastReplace = (ReplaceEdit) curEdit;
-          charEdits = lastReplace.getInternalEdits();
-          lastPos = 0;
-          lastIdx = 0;
-        }
-
-        String line = src.get(index) + "\n";
-        for (int c = 0; c < line.length();) {
-          if (charEdits == null || (charEdits.size() <= lastIdx)) {
-            appendShowBareCR(buf, line.substring(c), false);
-            break;
-          }
-
-          final Edit edit = charEdits.get(lastIdx);
-          final int b = side.getBegin(edit) - lastPos;
-          final int e = side.getEnd(edit) - lastPos;
-
-          if (c < b) {
-            // There is text at the start of this line that is common
-            // with the other side. Copy it with no style around it.
-            //
-            final int cmnLen = Math.min(b, line.length());
-            buf.openSpan();
-            buf.setStyleName("wdc");
-            appendShowBareCR(buf, line.substring(c, cmnLen), //
-                cmnLen == line.length() - 1);
-            buf.closeSpan();
-            c = cmnLen;
-          }
-
-          final int modLen = Math.min(e, line.length());
-          if (c < e && c < modLen) {
-            buf.openSpan();
-            buf.setStyleName(side.getStyleName());
-            appendShowBareCR(buf, line.substring(c, modLen), //
-                modLen == line.length() - 1);
-            buf.closeSpan();
-            if (modLen == line.length()) {
-              trailingEdits.add(index);
-            }
-            c = modLen;
-          }
-
-          if (e <= c) {
-            lastIdx++;
-          }
-        }
-        lastPos += line.length();
-
-      } else {
-        appendShowBareCR(buf, src.get(index), true);
-        buf.append('\n');
-      }
-    }
-    return buf;
-  }
-
-  private void appendShowBareCR(SafeHtmlBuilder buf, String src, boolean end) {
-    while (!src.isEmpty()) {
-      int cr = src.indexOf('\r');
-      if (cr < 0) {
-        buf.append(src);
-        return;
-
-      } else if (end) {
-        if (cr == src.length() - 1) {
-          buf.append(src.substring(0, cr + 1));
-          return;
-        }
-      } else if (cr == src.length() - 2 && src.charAt(cr + 1) == '\n') {
-        buf.append(src);
-        return;
-      }
-
-      buf.append(src.substring(0, cr));
-      buf.openSpan();
-      buf.setStyleName("wse");
-      buf.setAttribute("title", PrettifyConstants.C.wseBareCR());
-      buf.nbsp();
-      buf.closeSpan();
-      src = src.substring(cr + 1);
-    }
-  }
-
-  private int compare(int index, Edit edit) {
-    if (index < side.getBegin(edit)) {
-      return -1; // index occurs before the edit.
-
-    } else if (index < side.getEnd(edit)) {
-      return 0; // index occurs within the edit.
-
-    } else {
-      return 1; // index occurs after the edit.
-    }
-  }
-
-  private SafeHtml showTabAfterSpace(SafeHtml src) {
-    final String m = "( ( |<span[^>]*>|</span>)*\t)";
-    final String r = "<span class=\"wse\"" //
-        + " title=\"" + PrettifyConstants.C.wseTabAfterSpace() + "\"" //
-        + ">$1</span>";
-    src = src.replaceFirst("^" + m, r);
-    src = src.replaceAll("\n" + m, "\n" + r);
-    return src;
-  }
-
-  private SafeHtml showTrailingWhitespace(SafeHtml src) {
-    final String r = "<span class=\"wse\"" //
-        + " title=\"" + PrettifyConstants.C.wseTrailingSpace() + "\"" //
-        + ">$1</span>$2";
-    src = src.replaceAll("([ \t][ \t]*)(\r?(</span>)?\n)", r);
-    src = src.replaceFirst("([ \t][ \t]*)(\r?(</span>)?\n?)$", r);
-    return src;
-  }
-
-  private SafeHtml showLineEndings(SafeHtml src) {
-    final String r = "<span class=\"lecr\""
-        + " title=\"" + PrettifyConstants.C.leCR() + "\"" //
-        + ">\\\\r</span>";
-    src = src.replaceAll("\r", r);
-    return src;
-  }
-
-  private String expandTabs(String html) {
-    StringBuilder tmp = new StringBuilder();
-    int i = 0;
-    if (diffPrefs.showTabs) {
-      i = 1;
-    }
-    for (; i < diffPrefs.tabSize; i++) {
-      tmp.append("&nbsp;");
-    }
-    return html.replaceAll("\t", tmp.toString());
-  }
-
-  private String getFileType() {
-    String srcType = fileName;
-    if (srcType == null) {
-      return null;
-    }
-
-    int dot = srcType.lastIndexOf('.');
-    if (dot < 0) {
-      return null;
-    }
-
-    if (0 < dot) {
-      srcType = srcType.substring(dot + 1);
-    }
-
-    if ("txt".equalsIgnoreCase(srcType)) {
-      return null;
-    }
-
-    return srcType;
-  }
-}
diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrivateScopeImpl.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrivateScopeImpl.java
deleted file mode 100644
index 65ee212..0000000
--- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrivateScopeImpl.java
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright (C) 2010 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.prettify.client;
-
-import com.google.gwt.core.client.JavaScriptObject;
-import com.google.gwt.resources.client.TextResource;
-import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.NamedFrame;
-
-/**
- * Creates a private JavaScript environment, typically inside an IFrame.
- * <p>
- * Instances must be created through {@code GWT.create(PrivateScopeImpl.class)}.
- * A scope must remain attached to the primary document for its entire life.
- * Behavior is undefined if a scope is detached and attached again later. It is
- * best to attach the scope with {@code RootPanel.get().add(scope)} as soon as
- * it has been created.
- */
-public class PrivateScopeImpl extends Composite {
-  private static int scopeId;
-
-  protected final String scopeName;
-
-  public PrivateScopeImpl() {
-    scopeName = nextScopeName();
-
-    NamedFrame frame = new NamedFrame(scopeName);
-    frame.setUrl("javascript:''");
-    initWidget(frame);
-
-    setVisible(false);
-  }
-
-  public void compile(TextResource js) {
-    eval(js.getText());
-  }
-
-  public void eval(String js) {
-    nativeEval(getContext(), js);
-  }
-
-  public JavaScriptObject getContext() {
-    return nativeGetContext(scopeName);
-  }
-
-  private static String nextScopeName() {
-    return "_PrivateScope" + (++scopeId);
-  }
-
-  private static native void nativeEval(JavaScriptObject ctx, String js)
-  /*-{ ctx.eval(js); }-*/;
-
-  private static native JavaScriptObject nativeGetContext(String scopeName)
-  /*-{ return $wnd[scopeName]; }-*/;
-}
diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrivateScopeImplIE8.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrivateScopeImplIE8.java
deleted file mode 100644
index 0496d91..0000000
--- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrivateScopeImplIE8.java
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (C) 2010 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.prettify.client;
-
-import com.google.gwt.core.client.JavaScriptObject;
-
-/** MSIE requires us to initialize the document before we can use it. */
-public class PrivateScopeImplIE8 extends PrivateScopeImpl {
-  private JavaScriptObject context;
-
-  @Override
-  protected void onAttach() {
-    super.onAttach();
-    context = nativeInitContext(scopeName);
-  }
-
-  @Override
-  public JavaScriptObject getContext() {
-    return context;
-  }
-
-  private static native JavaScriptObject nativeInitContext(String scopeName)
-  /*-{
-    var fe = $wnd[scopeName];
-    fe.document.write(
-        '<script>'
-      + 'parent._PrivateScopeNewChild = this;'
-      + '</' + 'script>'
-    );
-    var ctx = $wnd._PrivateScopeNewChild;
-    $wnd._PrivateScopeNewChild = undefined;
-    return ctx;
-  }-*/;
-}
diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/Resources.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/Resources.java
deleted file mode 100644
index 93c2988..0000000
--- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/Resources.java
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (C) 2009 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.prettify.client;
-
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.resources.client.ClientBundle;
-import com.google.gwt.resources.client.CssResource;
-import com.google.gwt.resources.client.TextResource;
-
-/** Loads the minimized form of prettify into the client. */
-interface Resources extends ClientBundle {
-  static final Resources I = GWT.create(Resources.class);
-
-  @Source("prettify.css")
-  CssResource prettify_css();
-
-  @Source("gerrit.css")
-  CssResource gerrit_css();
-
-  @Source("prettify.js")
-  TextResource core();
-
-  @Source("lang-apollo.js") TextResource lang_apollo();
-  @Source("lang-basic.js") TextResource lang_basic();
-  @Source("lang-clj.js") TextResource lang_clj();
-  @Source("lang-css.js") TextResource lang_css();
-  @Source("lang-dart.js") TextResource lang_dart();
-  @Source("lang-erlang.js") TextResource lang_erlang();
-  @Source("lang-go.js") TextResource lang_go();
-  @Source("lang-hs.js") TextResource lang_hs();
-  @Source("lang-lisp.js") TextResource lang_lisp();
-  @Source("lang-llvm.js") TextResource lang_llvm();
-  @Source("lang-lua.js") TextResource lang_lua();
-  @Source("lang-matlab.js") TextResource lang_matlab();
-  @Source("lang-ml.js") TextResource lang_ml();
-  @Source("lang-mumps.js") TextResource lang_mumps();
-  @Source("lang-n.js") TextResource lang_n();
-  @Source("lang-pascal.js") TextResource lang_pascal();
-  @Source("lang-proto.js") TextResource lang_proto();
-  @Source("lang-r.js") TextResource lang_r();
-  @Source("lang-rd.js") TextResource lang_rd();
-  @Source("lang-scala.js") TextResource lang_scala();
-  @Source("lang-sql.js") TextResource lang_sql();
-  @Source("lang-tcl.js") TextResource lang_tcl();
-  @Source("lang-tex.js") TextResource lang_tex();
-  @Source("lang-vb.js") TextResource lang_vb();
-  @Source("lang-vhdl.js") TextResource lang_vhdl();
-  @Source("lang-wiki.js") TextResource lang_wiki();
-  @Source("lang-xq.js") TextResource lang_xq();
-  @Source("lang-yaml.js") TextResource lang_yaml();
-}
diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/SparseHtmlFile.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/SparseHtmlFile.java
deleted file mode 100644
index 3fd34bf..0000000
--- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/SparseHtmlFile.java
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (C) 2010 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.prettify.client;
-
-import com.google.gwtexpui.safehtml.client.SafeHtml;
-
-public interface SparseHtmlFile {
-  /** @return the line of formatted HTML. */
-  SafeHtml getSafeHtmlLine(int lineNo);
-
-  /** @return the number of lines in this sparse list. */
-  int size();
-
-  /** @return true if the line is valid in this sparse list. */
-  boolean contains(int idx);
-
-  /** @return true if this line ends in the middle of a character edit span. */
-  boolean hasTrailingEdit(int idx);
-}
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/gerrit.css b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/gerrit.css
deleted file mode 100644
index 23e7e46..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/gerrit.css
+++ /dev/null
@@ -1,98 +0,0 @@
-/* Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-@external .wse;
-@external .lecr;
-@external .vt;
-@external .wdd;
-@external .wdi;
-
-@external .str;
-@external .kwd;
-@external .com;
-@external .typ;
-@external .lit;
-@external .pun;
-@external .pln;
-@external .tag;
-@external .atn;
-@external .atv;
-@external .dec;
-
-.wse {
-  background: red;
-  cursor: pointer;
-}
-
-.lecr {
-  border-bottom: #aaaaaa 1px dashed;
-  border-left: #aaaaaa 1px dashed;
-  padding-bottom: 0px;
-  margin: 0px 2px;
-  padding-left: 2px;
-  padding-right: 2px;
-  border-top: #aaaaaa 1px dashed;
-  border-right: #aaaaaa 1px dashed;
-  padding-top: 0px;
-  cursor: pointer;
-}
-
-.vt,
-.vt .str,
-.vt .kwd,
-.vt .com,
-.vt .typ,
-.vt .lit,
-.vt .pun,
-.vt .pln,
-.vt .tag,
-.vt .atn,
-.vt .atv,
-.vt .dec {
-  color: red;
-}
-
-.wdd {
-  background: #FAA;
-}
-.wdi {
-  background: #9F9;
-}
-
-/* Use special rules for special styles contained within a whitespace
- * error.  For these we want the whitespace error to take precedence
- * so we have to override the contained style.
- */
-.wse .vt, .wdd .vt,
-.wse .vt .pun, .wdd .vt .pun,
-.wse .vt .str, .wdd .vt .str,
-.wse .vt .kwd, .wdd .vt .kwd,
-.wse .vt .com, .wdd .vt .com,
-.wse .vt .typ, .wdd .vt .typ,
-.wse .vt .lit, .wdd .vt .lit,
-.wse .vt .pun, .wdd .vt .pun,
-.wse .vt .pln, .wdd .vt .pln,
-.wse .vt .tag, .wdd .vt .tag,
-.wse .vt .atn, .wdd .vt .atn,
-.wse .vt .atv, .wdd .vt .atv,
-.wse .vt .dec, .wdd .vt .dec {
-  color: black;
-}
-.wse .wdd {
-  background: red;
-}
-.wse .wdi {
-  background: red;
-}
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-apollo.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-apollo.js
deleted file mode 100644
index 99e4a97..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-apollo.js
+++ /dev/null
@@ -1,2 +0,0 @@
-PR.registerLangHandler(PR.createSimpleLexer([["com",/^#[^\n\r]*/,null,"#"],["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,null,'"']],[["kwd",/^(?:ADS|AD|AUG|BZF|BZMF|CAE|CAF|CA|CCS|COM|CS|DAS|DCA|DCOM|DCS|DDOUBL|DIM|DOUBLE|DTCB|DTCF|DV|DXCH|EDRUPT|EXTEND|INCR|INDEX|NDX|INHINT|LXCH|MASK|MSK|MP|MSU|NOOP|OVSK|QXCH|RAND|READ|RELINT|RESUME|RETURN|ROR|RXOR|SQUARE|SU|TCR|TCAA|OVSK|TCF|TC|TS|WAND|WOR|WRITE|XCH|XLQ|XXALQ|ZL|ZQ|ADD|ADZ|SUB|SUZ|MPY|MPR|MPZ|DVP|COM|ABS|CLA|CLZ|LDQ|STO|STQ|ALS|LLS|LRS|TRA|TSQ|TMI|TOV|AXT|TIX|DLY|INP|OUT)\s/,
-null],["typ",/^(?:-?GENADR|=MINUS|2BCADR|VN|BOF|MM|-?2CADR|-?[1-6]DNADR|ADRES|BBCON|[ES]?BANK=?|BLOCK|BNKSUM|E?CADR|COUNT\*?|2?DEC\*?|-?DNCHAN|-?DNPTR|EQUALS|ERASE|MEMORY|2?OCT|REMADR|SETLOC|SUBRO|ORG|BSS|BES|SYN|EQU|DEFINE|END)\s/,null],["lit",/^'(?:-*(?:\w|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?)?/],["pln",/^-*(?:[!-z]|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?/],["pun",/^[^\w\t\n\r "'-);\\\xa0]+/]]),["apollo","agc","aea"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-basic.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-basic.js
deleted file mode 100644
index 6b784d4..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-basic.js
+++ /dev/null
@@ -1,3 +0,0 @@
-var a=null;
-PR.registerLangHandler(PR.createSimpleLexer([["str",/^"(?:[^\n\r"\\]|\\.)*(?:"|$)/,a,'"'],["pln",/^\s+/,a," \r\n\t\u00a0"]],[["com",/^REM[^\n\r]*/,a],["kwd",/^\b(?:AND|CLOSE|CLR|CMD|CONT|DATA|DEF ?FN|DIM|END|FOR|GET|GOSUB|GOTO|IF|INPUT|LET|LIST|LOAD|NEW|NEXT|NOT|ON|OPEN|OR|POKE|PRINT|READ|RESTORE|RETURN|RUN|SAVE|STEP|STOP|SYS|THEN|TO|VERIFY|WAIT)\b/,a],["pln",/^[a-z][^\W_]?(?:\$|%)?/i,a],["lit",/^(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?/i,a,"0123456789"],["pun",
-/^.[^\s\w"$%.]*/,a]]),["basic","cbm"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-clj.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-clj.js
deleted file mode 100644
index 1bb539c..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-clj.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- Copyright (C) 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-var a=null;
-PR.registerLangHandler(PR.createSimpleLexer([["opn",/^[([{]+/,a,"([{"],["clo",/^[)\]}]+/,a,")]}"],["com",/^;[^\n\r]*/,a,";"],["pln",/^[\t\n\r \xa0]+/,a,"\t\n\r \u00a0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,a,'"']],[["kwd",/^(?:def|if|do|let|quote|var|fn|loop|recur|throw|try|monitor-enter|monitor-exit|defmacro|defn|defn-|macroexpand|macroexpand-1|for|doseq|dosync|dotimes|and|or|when|not|assert|doto|proxy|defstruct|first|rest|cons|defprotocol|deftype|defrecord|reify|defmulti|defmethod|meta|with-meta|ns|in-ns|create-ns|import|intern|refer|alias|namespace|resolve|ref|deref|refset|new|set!|memfn|to-array|into-array|aset|gen-class|reduce|map|filter|find|nil?|empty?|hash-map|hash-set|vec|vector|seq|flatten|reverse|assoc|dissoc|list|list?|disj|get|union|difference|intersection|extend|extend-type|extend-protocol|prn)\b/,a],
-["typ",/^:[\dA-Za-z-]+/]]),["clj"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-css.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-css.js
deleted file mode 100644
index d7a4640..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-css.js
+++ /dev/null
@@ -1,2 +0,0 @@
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n\u000c"]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]+)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],
-["com",/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}\b/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-dart.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-dart.js
deleted file mode 100644
index eefccc9..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-dart.js
+++ /dev/null
@@ -1,3 +0,0 @@
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"]],[["com",/^#!.*/],["kwd",/^\b(?:import|library|part of|part|as|show|hide)\b/i],["com",/^\/\/.*/],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["kwd",/^\b(?:class|interface)\b/i],["kwd",/^\b(?:assert|break|case|catch|continue|default|do|else|finally|for|if|in|is|new|return|super|switch|this|throw|try|while)\b/i],["kwd",/^\b(?:abstract|const|extends|factory|final|get|implements|native|operator|set|static|typedef|var)\b/i],
-["typ",/^\b(?:bool|double|dynamic|int|num|object|string|void)\b/i],["kwd",/^\b(?:false|null|true)\b/i],["str",/^r?'''[\S\s]*?[^\\]'''/],["str",/^r?"""[\S\s]*?[^\\]"""/],["str",/^r?'('|[^\n\f\r]*?[^\\]')/],["str",/^r?"("|[^\n\f\r]*?[^\\]")/],["pln",/^[$_a-z]\w*/i],["pun",/^[!%&*+/:<-?^|~-]/],["lit",/^\b0x[\da-f]+/i],["lit",/^\b\d+(?:\.\d*)?(?:e[+-]?\d+)?/i],["lit",/^\b\.\d+(?:e[+-]?\d+)?/i],["pun",/^[(),.;[\]{}]/]]),
-["dart"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-erlang.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-erlang.js
deleted file mode 100644
index 27214a5..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-erlang.js
+++ /dev/null
@@ -1,2 +0,0 @@
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t-\r ]+/,null,"\t\n\u000b\u000c\r "],["str",/^"(?:[^\n\f\r"\\]|\\[\S\s])*(?:"|$)/,null,'"'],["lit",/^[a-z]\w*/],["lit",/^'(?:[^\n\f\r'\\]|\\[^&])+'?/,null,"'"],["lit",/^\?[^\t\n ({]+/,null,"?"],["lit",/^(?:0o[0-7]+|0x[\da-f]+|\d+(?:\.\d+)?(?:e[+-]?\d+)?)/i,null,"0123456789"]],[["com",/^%[^\n]*/],["kwd",/^(?:module|attributes|do|let|in|letrec|apply|call|primop|case|of|end|when|fun|try|catch|receive|after|char|integer|float,atom,string,var)\b/],
-["kwd",/^-[_a-z]+/],["typ",/^[A-Z_]\w*/],["pun",/^[,.;]/]]),["erlang","erl"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-go.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-go.js
deleted file mode 100644
index 1caca23..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-go.js
+++ /dev/null
@@ -1 +0,0 @@
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["pln",/^(?:"(?:[^"\\]|\\[\S\s])*(?:"|$)|'(?:[^'\\]|\\[\S\s])+(?:'|$)|`[^`]*(?:`|$))/,null,"\"'"]],[["com",/^(?:\/\/[^\n\r]*|\/\*[\S\s]*?\*\/)/],["pln",/^(?:[^"'/`]|\/(?![*/]))+/]]),["go"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-hs.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-hs.js
deleted file mode 100644
index ff3729b..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-hs.js
+++ /dev/null
@@ -1,2 +0,0 @@
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t-\r ]+/,null,"\t\n\u000b\u000c\r "],["str",/^"(?:[^\n\f\r"\\]|\\[\S\s])*(?:"|$)/,null,'"'],["str",/^'(?:[^\n\f\r'\\]|\\[^&])'?/,null,"'"],["lit",/^(?:0o[0-7]+|0x[\da-f]+|\d+(?:\.\d+)?(?:e[+-]?\d+)?)/i,null,"0123456789"]],[["com",/^(?:--+[^\n\f\r]*|{-(?:[^-]|-+[^}-])*-})/],["kwd",/^(?:case|class|data|default|deriving|do|else|if|import|in|infix|infixl|infixr|instance|let|module|newtype|of|then|type|where|_)(?=[^\d'A-Za-z]|$)/,
-null],["pln",/^(?:[A-Z][\w']*\.)*[A-Za-z][\w']*/],["pun",/^[^\d\t-\r "'A-Za-z]+/]]),["hs"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-lisp.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-lisp.js
deleted file mode 100644
index 9c8cfa5..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-lisp.js
+++ /dev/null
@@ -1,3 +0,0 @@
-var a=null;
-PR.registerLangHandler(PR.createSimpleLexer([["opn",/^\(+/,a,"("],["clo",/^\)+/,a,")"],["com",/^;[^\n\r]*/,a,";"],["pln",/^[\t\n\r \xa0]+/,a,"\t\n\r \u00a0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,a,'"']],[["kwd",/^(?:block|c[ad]+r|catch|con[ds]|def(?:ine|un)|do|eq|eql|equal|equalp|eval-when|flet|format|go|if|labels|lambda|let|load-time-value|locally|macrolet|multiple-value-call|nil|progn|progv|quote|require|return-from|setq|symbol-macrolet|t|tagbody|the|throw|unwind)\b/,a],
-["lit",/^[+-]?(?:[#0]x[\da-f]+|\d+\/\d+|(?:\.\d+|\d+(?:\.\d*)?)(?:[de][+-]?\d+)?)/i],["lit",/^'(?:-*(?:\w|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?)?/],["pln",/^-*(?:[_a-z]|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?/i],["pun",/^[^\w\t\n\r "'-);\\\xa0]+/]]),["cl","el","lisp","lsp","scm","ss","rkt"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-llvm.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-llvm.js
deleted file mode 100644
index 16fade2..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-llvm.js
+++ /dev/null
@@ -1 +0,0 @@
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["str",/^!?"(?:[^"\\]|\\[\S\s])*(?:"|$)/,null,'"'],["com",/^;[^\n\r]*/,null,";"]],[["pln",/^[!%@](?:[$\-.A-Z_a-z][\w$\-.]*|\d+)/],["kwd",/^[^\W\d]\w*/,null],["lit",/^\d+\.\d+/],["lit",/^(?:\d+|0[Xx][\dA-Fa-f]+)/],["pun",/^[(-*,:<->[\]{}]|\.\.\.$/]]),["llvm","ll"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-lua.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-lua.js
deleted file mode 100644
index 7e44cca..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-lua.js
+++ /dev/null
@@ -1,2 +0,0 @@
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["str",/^(?:"(?:[^"\\]|\\[\S\s])*(?:"|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$))/,null,"\"'"]],[["com",/^--(?:\[(=*)\[[\S\s]*?(?:]\1]|$)|[^\n\r]*)/],["str",/^\[(=*)\[[\S\s]*?(?:]\1]|$)/],["kwd",/^(?:and|break|do|else|elseif|end|false|for|function|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/,null],["lit",/^[+-]?(?:0x[\da-f]+|(?:\.\d+|\d+(?:\.\d*)?)(?:e[+-]?\d+)?)/i],
-["pln",/^[_a-z]\w*/i],["pun",/^[^\w\t\n\r \xa0][^\w\t\n\r "'+=\xa0-]*/]]),["lua"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-matlab.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-matlab.js
deleted file mode 100644
index d0d3516..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-matlab.js
+++ /dev/null
@@ -1,6 +0,0 @@
-var a=null,b=window.PR,c=[[b.PR_PLAIN,/^[\t-\r \xa0]+/,a," \t\r\n\u000b\u000c\u00a0"],[b.PR_COMMENT,/^%{[^%]*%+(?:[^%}][^%]*%+)*}/,a],[b.PR_COMMENT,/^%[^\n\r]*/,a,"%"],["syscmd",/^![^\n\r]*/,a,"!"]],d=[["linecont",/^\.\.\.\s*[\n\r]/,a],["err",/^\?\?\? [^\n\r]*/,a],["wrn",/^Warning: [^\n\r]*/,a],["codeoutput",/^>>\s+/,a],["codeoutput",/^octave:\d+>\s+/,a],["lang-matlab-operators",/^((?:[A-Za-z]\w*(?:\.[A-Za-z]\w*)*|[).\]}])')/,a],["lang-matlab-identifiers",/^([A-Za-z]\w*(?:\.[A-Za-z]\w*)*)(?!')/,a],
-[b.PR_STRING,/^'(?:[^']|'')*'/,a],[b.PR_LITERAL,/^[+-]?\.?\d+(?:\.\d*)?(?:[Ee][+-]?\d+)?[ij]?/,a],[b.PR_TAG,/^[()[\]{}]/,a],[b.PR_PUNCTUATION,/^[!&*-/:->@\\^|~]/,a]],e=[["lang-matlab-identifiers",/^([A-Za-z]\w*(?:\.[A-Za-z]\w*)*)/,a],[b.PR_TAG,/^[()[\]{}]/,a],[b.PR_PUNCTUATION,/^[!&*-/:->@\\^|~]/,a],["transpose",/^'/,a]];
-b.registerLangHandler(b.createSimpleLexer([],[[b.PR_KEYWORD,/^\b(?:break|case|catch|classdef|continue|else|elseif|end|for|function|global|if|otherwise|parfor|persistent|return|spmd|switch|try|while)\b/,a],["const",/^\b(?:true|false|inf|Inf|nan|NaN|eps|pi|ans|nargin|nargout|varargin|varargout)\b/,a],[b.PR_TYPE,/^\b(?:cell|struct|char|double|single|logical|u?int(?:8|16|32|64)|sparse)\b/,a],["fun",/^\b(?:abs|accumarray|acos(?:d|h)?|acot(?:d|h)?|acsc(?:d|h)?|actxcontrol(?:list|select)?|actxGetRunningServer|actxserver|addlistener|addpath|addpref|addtodate|airy|align|alim|all|allchild|alpha|alphamap|amd|ancestor|and|angle|annotation|any|area|arrayfun|asec(?:d|h)?|asin(?:d|h)?|assert|assignin|atan[2dh]?|audiodevinfo|audioplayer|audiorecorder|aufinfo|auread|autumn|auwrite|avifile|aviinfo|aviread|axes|axis|balance|bar(?:3|3h|h)?|base2dec|beep|BeginInvoke|bench|bessel[h-ky]|beta|betainc|betaincinv|betaln|bicg|bicgstab|bicgstabl|bin2dec|bitand|bitcmp|bitget|bitmax|bitnot|bitor|bitset|bitshift|bitxor|blanks|blkdiag|bone|box|brighten|brush|bsxfun|builddocsearchdb|builtin|bvp4c|bvp5c|bvpget|bvpinit|bvpset|bvpxtend|calendar|calllib|callSoapService|camdolly|cameratoolbar|camlight|camlookat|camorbit|campan|campos|camproj|camroll|camtarget|camup|camva|camzoom|cart2pol|cart2sph|cast|cat|caxis|cd|cdf2rdf|cdfepoch|cdfinfo|cdflib(?:.(?:close|closeVar|computeEpoch|computeEpoch16|create|createAttr|createVar|delete|deleteAttr|deleteAttrEntry|deleteAttrgEntry|deleteVar|deleteVarRecords|epoch16Breakdown|epochBreakdown|getAttrEntry|getAttrgEntry|getAttrMaxEntry|getAttrMaxgEntry|getAttrName|getAttrNum|getAttrScope|getCacheSize|getChecksum|getCompression|getCompressionCacheSize|getConstantNames|getConstantValue|getCopyright|getFileBackward|getFormat|getLibraryCopyright|getLibraryVersion|getMajority|getName|getNumAttrEntries|getNumAttrgEntries|getNumAttributes|getNumgAttributes|getReadOnlyMode|getStageCacheSize|getValidate|getVarAllocRecords|getVarBlockingFactor|getVarCacheSize|getVarCompression|getVarData|getVarMaxAllocRecNum|getVarMaxWrittenRecNum|getVarName|getVarNum|getVarNumRecsWritten|getVarPadValue|getVarRecordData|getVarReservePercent|getVarsMaxWrittenRecNum|getVarSparseRecords|getVersion|hyperGetVarData|hyperPutVarData|inquire|inquireAttr|inquireAttrEntry|inquireAttrgEntry|inquireVar|open|putAttrEntry|putAttrgEntry|putVarData|putVarRecordData|renameAttr|renameVar|setCacheSize|setChecksum|setCompression|setCompressionCacheSize|setFileBackward|setFormat|setMajority|setReadOnlyMode|setStageCacheSize|setValidate|setVarAllocBlockRecords|setVarBlockingFactor|setVarCacheSize|setVarCompression|setVarInitialRecs|setVarPadValue|SetVarReservePercent|setVarsCacheSize|setVarSparseRecords))?|cdfread|cdfwrite|ceil|cell2mat|cell2struct|celldisp|cellfun|cellplot|cellstr|cgs|checkcode|checkin|checkout|chol|cholinc|cholupdate|circshift|cla|clabel|class|clc|clear|clearvars|clf|clipboard|clock|close|closereq|cmopts|cmpermute|cmunique|colamd|colon|colorbar|colordef|colormap|colormapeditor|colperm|Combine|comet|comet3|commandhistory|commandwindow|compan|compass|complex|computer|cond|condeig|condest|coneplot|conj|containers.Map|contour(?:[3cf]|slice)?|contrast|conv|conv2|convhull|convhulln|convn|cool|copper|copyfile|copyobj|corrcoef|cos(?:d|h)?|cot(?:d|h)?|cov|cplxpair|cputime|createClassFromWsdl|createSoapMessage|cross|csc(?:d|h)?|csvread|csvwrite|ctranspose|cumprod|cumsum|cumtrapz|curl|customverctrl|cylinder|daqread|daspect|datacursormode|datatipinfo|date|datenum|datestr|datetick|datevec|dbclear|dbcont|dbdown|dblquad|dbmex|dbquit|dbstack|dbstatus|dbstep|dbstop|dbtype|dbup|dde23|ddeget|ddesd|ddeset|deal|deblank|dec2base|dec2bin|dec2hex|decic|deconv|del2|delaunay|delaunay3|delaunayn|DelaunayTri|delete|demo|depdir|depfun|det|detrend|deval|diag|dialog|diary|diff|diffuse|dir|disp|display|dither|divergence|dlmread|dlmwrite|dmperm|doc|docsearch|dos|dot|dragrect|drawnow|dsearch|dsearchn|dynamicprops|echo|echodemo|edit|eig|eigs|ellipj|ellipke|ellipsoid|empty|enableNETfromNetworkDrive|enableservice|EndInvoke|enumeration|eomday|eq|erf|erfc|erfcinv|erfcx|erfinv|error|errorbar|errordlg|etime|etree|etreeplot|eval|evalc|evalin|event.(?:EventData|listener|PropertyEvent|proplistener)|exifread|exist|exit|exp|expint|expm|expm1|export2wsdlg|eye|ezcontour|ezcontourf|ezmesh|ezmeshc|ezplot|ezplot3|ezpolar|ezsurf|ezsurfc|factor|factorial|fclose|feather|feature|feof|ferror|feval|fft|fft2|fftn|fftshift|fftw|fgetl|fgets|fieldnames|figure|figurepalette|fileattrib|filebrowser|filemarker|fileparts|fileread|filesep|fill|fill3|filter|filter2|find|findall|findfigs|findobj|findstr|finish|fitsdisp|fitsinfo|fitsread|fitswrite|fix|flag|flipdim|fliplr|flipud|floor|flow|fminbnd|fminsearch|fopen|format|fplot|fprintf|frame2im|fread|freqspace|frewind|fscanf|fseek|ftell|FTP|full|fullfile|func2str|functions|funm|fwrite|fzero|gallery|gamma|gammainc|gammaincinv|gammaln|gca|gcbf|gcbo|gcd|gcf|gco|ge|genpath|genvarname|get|getappdata|getenv|getfield|getframe|getpixelposition|getpref|ginput|gmres|gplot|grabcode|gradient|gray|graymon|grid|griddata(?:3|n)?|griddedInterpolant|gsvd|gt|gtext|guidata|guide|guihandles|gunzip|gzip|h5create|h5disp|h5info|h5read|h5readatt|h5write|h5writeatt|hadamard|handle|hankel|hdf|hdf5|hdf5info|hdf5read|hdf5write|hdfinfo|hdfread|hdftool|help|helpbrowser|helpdesk|helpdlg|helpwin|hess|hex2dec|hex2num|hgexport|hggroup|hgload|hgsave|hgsetget|hgtransform|hidden|hilb|hist|histc|hold|home|horzcat|hostid|hot|hsv|hsv2rgb|hypot|ichol|idivide|ifft|ifft2|ifftn|ifftshift|ilu|im2frame|im2java|imag|image|imagesc|imapprox|imfinfo|imformats|import|importdata|imread|imwrite|ind2rgb|ind2sub|inferiorto|info|inline|inmem|inpolygon|input|inputdlg|inputname|inputParser|inspect|instrcallback|instrfind|instrfindall|int2str|integral(?:2|3)?|interp(?:1|1q|2|3|ft|n)|interpstreamspeed|intersect|intmax|intmin|inv|invhilb|ipermute|isa|isappdata|iscell|iscellstr|ischar|iscolumn|isdir|isempty|isequal|isequaln|isequalwithequalnans|isfield|isfinite|isfloat|isglobal|ishandle|ishghandle|ishold|isinf|isinteger|isjava|iskeyword|isletter|islogical|ismac|ismatrix|ismember|ismethod|isnan|isnumeric|isobject|isocaps|isocolors|isonormals|isosurface|ispc|ispref|isprime|isprop|isreal|isrow|isscalar|issorted|isspace|issparse|isstr|isstrprop|isstruct|isstudent|isunix|isvarname|isvector|javaaddpath|javaArray|javachk|javaclasspath|javacomponent|javaMethod|javaMethodEDT|javaObject|javaObjectEDT|javarmpath|jet|keyboard|kron|lasterr|lasterror|lastwarn|lcm|ldivide|ldl|le|legend|legendre|length|libfunctions|libfunctionsview|libisloaded|libpointer|libstruct|license|light|lightangle|lighting|lin2mu|line|lines|linkaxes|linkdata|linkprop|linsolve|linspace|listdlg|listfonts|load|loadlibrary|loadobj|log|log10|log1p|log2|loglog|logm|logspace|lookfor|lower|ls|lscov|lsqnonneg|lsqr|lt|lu|luinc|magic|makehgtform|mat2cell|mat2str|material|matfile|matlab.io.MatFile|matlab.mixin.(?:Copyable|Heterogeneous(?:.getDefaultScalarElement)?)|matlabrc|matlabroot|max|maxNumCompThreads|mean|median|membrane|memmapfile|memory|menu|mesh|meshc|meshgrid|meshz|meta.(?:class(?:.fromName)?|DynamicProperty|EnumeratedValue|event|MetaData|method|package(?:.(?:fromName|getAllPackages))?|property)|metaclass|methods|methodsview|mex(?:.getCompilerConfigurations)?|MException|mexext|mfilename|min|minres|minus|mislocked|mkdir|mkpp|mldivide|mlint|mlintrpt|mlock|mmfileinfo|mmreader|mod|mode|more|move|movefile|movegui|movie|movie2avi|mpower|mrdivide|msgbox|mtimes|mu2lin|multibandread|multibandwrite|munlock|namelengthmax|nargchk|narginchk|nargoutchk|native2unicode|nccreate|ncdisp|nchoosek|ncinfo|ncread|ncreadatt|ncwrite|ncwriteatt|ncwriteschema|ndgrid|ndims|ne|NET(?:.(?:addAssembly|Assembly|convertArray|createArray|createGeneric|disableAutoRelease|enableAutoRelease|GenericClass|invokeGenericMethod|NetException|setStaticProperty))?|netcdf.(?:abort|close|copyAtt|create|defDim|defGrp|defVar|defVarChunking|defVarDeflate|defVarFill|defVarFletcher32|delAtt|endDef|getAtt|getChunkCache|getConstant|getConstantNames|getVar|inq|inqAtt|inqAttID|inqAttName|inqDim|inqDimID|inqDimIDs|inqFormat|inqGrpName|inqGrpNameFull|inqGrpParent|inqGrps|inqLibVers|inqNcid|inqUnlimDims|inqVar|inqVarChunking|inqVarDeflate|inqVarFill|inqVarFletcher32|inqVarID|inqVarIDs|open|putAtt|putVar|reDef|renameAtt|renameDim|renameVar|setChunkCache|setDefaultFormat|setFill|sync)|newplot|nextpow2|nnz|noanimate|nonzeros|norm|normest|not|notebook|now|nthroot|null|num2cell|num2hex|num2str|numel|nzmax|ode(?:113|15i|15s|23|23s|23t|23tb|45)|odeget|odeset|odextend|onCleanup|ones|open|openfig|opengl|openvar|optimget|optimset|or|ordeig|orderfields|ordqz|ordschur|orient|orth|pack|padecoef|pagesetupdlg|pan|pareto|parseSoapResponse|pascal|patch|path|path2rc|pathsep|pathtool|pause|pbaspect|pcg|pchip|pcode|pcolor|pdepe|pdeval|peaks|perl|perms|permute|pie|pink|pinv|planerot|playshow|plot|plot3|plotbrowser|plotedit|plotmatrix|plottools|plotyy|plus|pol2cart|polar|poly|polyarea|polyder|polyeig|polyfit|polyint|polyval|polyvalm|pow2|power|ppval|prefdir|preferences|primes|print|printdlg|printopt|printpreview|prod|profile|profsave|propedit|propertyeditor|psi|publish|PutCharArray|PutFullMatrix|PutWorkspaceData|pwd|qhull|qmr|qr|qrdelete|qrinsert|qrupdate|quad|quad2d|quadgk|quadl|quadv|questdlg|quit|quiver|quiver3|qz|rand|randi|randn|randperm|RandStream(?:.(?:create|getDefaultStream|getGlobalStream|list|setDefaultStream|setGlobalStream))?|rank|rat|rats|rbbox|rcond|rdivide|readasync|real|reallog|realmax|realmin|realpow|realsqrt|record|rectangle|rectint|recycle|reducepatch|reducevolume|refresh|refreshdata|regexp|regexpi|regexprep|regexptranslate|rehash|rem|Remove|RemoveAll|repmat|reset|reshape|residue|restoredefaultpath|rethrow|rgb2hsv|rgb2ind|rgbplot|ribbon|rmappdata|rmdir|rmfield|rmpath|rmpref|rng|roots|rose|rosser|rot90|rotate|rotate3d|round|rref|rsf2csf|run|save|saveas|saveobj|savepath|scatter|scatter3|schur|sec|secd|sech|selectmoveresize|semilogx|semilogy|sendmail|serial|set|setappdata|setdiff|setenv|setfield|setpixelposition|setpref|setstr|setxor|shading|shg|shiftdim|showplottool|shrinkfaces|sign|sin(?:d|h)?|size|slice|smooth3|snapnow|sort|sortrows|sound|soundsc|spalloc|spaugment|spconvert|spdiags|specular|speye|spfun|sph2cart|sphere|spinmap|spline|spones|spparms|sprand|sprandn|sprandsym|sprank|spring|sprintf|spy|sqrt|sqrtm|squeeze|ss2tf|sscanf|stairs|startup|std|stem|stem3|stopasync|str2double|str2func|str2mat|str2num|strcat|strcmp|strcmpi|stream2|stream3|streamline|streamparticles|streamribbon|streamslice|streamtube|strfind|strjust|strmatch|strncmp|strncmpi|strread|strrep|strtok|strtrim|struct2cell|structfun|strvcat|sub2ind|subplot|subsasgn|subsindex|subspace|subsref|substruct|subvolume|sum|summer|superclasses|superiorto|support|surf|surf2patch|surface|surfc|surfl|surfnorm|svd|svds|swapbytes|symamd|symbfact|symmlq|symrcm|symvar|system|tan(?:d|h)?|tar|tempdir|tempname|tetramesh|texlabel|text|textread|textscan|textwrap|tfqmr|throw|tic|Tiff(?:.(?:getTagNames|getVersion))?|timer|timerfind|timerfindall|times|timeseries|title|toc|todatenum|toeplitz|toolboxdir|trace|transpose|trapz|treelayout|treeplot|tril|trimesh|triplequad|triplot|TriRep|TriScatteredInterp|trisurf|triu|tscollection|tsearch|tsearchn|tstool|type|typecast|uibuttongroup|uicontextmenu|uicontrol|uigetdir|uigetfile|uigetpref|uiimport|uimenu|uiopen|uipanel|uipushtool|uiputfile|uiresume|uisave|uisetcolor|uisetfont|uisetpref|uistack|uitable|uitoggletool|uitoolbar|uiwait|uminus|undocheckout|unicode2native|union|unique|unix|unloadlibrary|unmesh|unmkpp|untar|unwrap|unzip|uplus|upper|urlread|urlwrite|usejava|userpath|validateattributes|validatestring|vander|var|vectorize|ver|verctrl|verLessThan|version|vertcat|VideoReader(?:.isPlatformSupported)?|VideoWriter(?:.getProfiles)?|view|viewmtx|visdiff|volumebounds|voronoi|voronoin|wait|waitbar|waitfor|waitforbuttonpress|warndlg|warning|waterfall|wavfinfo|wavplay|wavread|wavrecord|wavwrite|web|weekday|what|whatsnew|which|whitebg|who|whos|wilkinson|winopen|winqueryreg|winter|wk1finfo|wk1read|wk1write|workspace|xlabel|xlim|xlsfinfo|xlsread|xlswrite|xmlread|xmlwrite|xor|xslt|ylabel|ylim|zeros|zip|zlabel|zlim|zoom)\b/,
-a],["fun_tbx",/^\b(?:addedvarplot|andrewsplot|anova[12n]|ansaribradley|aoctool|barttest|bbdesign|beta(?:cdf|fit|inv|like|pdf|rnd|stat)|bino(?:cdf|fit|inv|pdf|rnd|stat)|biplot|bootci|bootstrp|boxplot|candexch|candgen|canoncorr|capability|capaplot|caseread|casewrite|categorical|ccdesign|cdfplot|chi2(?:cdf|gof|inv|pdf|rnd|stat)|cholcov|Classification(?:BaggedEnsemble|Discriminant(?:.(?:fit|make|template))?|Ensemble|KNN(?:.(?:fit|template))?|PartitionedEnsemble|PartitionedModel|Tree(?:.(?:fit|template))?)|classify|classregtree|cluster|clusterdata|cmdscale|combnk|Compact(?:Classification(?:Discriminant|Ensemble|Tree)|Regression(?:Ensemble|Tree)|TreeBagger)|confusionmat|controlchart|controlrules|cophenet|copula(?:cdf|fit|param|pdf|rnd|stat)|cordexch|corr|corrcov|coxphfit|createns|crosstab|crossval|cvpartition|datasample|dataset|daugment|dcovary|dendrogram|dfittool|disttool|dummyvar|dwtest|ecdf|ecdfhist|ev(?:cdf|fit|inv|like|pdf|rnd|stat)|ExhaustiveSearcher|exp(?:cdf|fit|inv|like|pdf|rnd|stat)|factoran|fcdf|ff2n|finv|fitdist|fitensemble|fpdf|fracfact|fracfactgen|friedman|frnd|fstat|fsurfht|fullfact|gagerr|gam(?:cdf|fit|inv|like|pdf|rnd|stat)|GeneralizedLinearModel(?:.fit)?|geo(?:cdf|inv|mean|pdf|rnd|stat)|gev(?:cdf|fit|inv|like|pdf|rnd|stat)|gline|glmfit|glmval|glyphplot|gmdistribution(?:.fit)?|gname|gp(?:cdf|fit|inv|like|pdf|rnd|stat)|gplotmatrix|grp2idx|grpstats|gscatter|haltonset|harmmean|hist3|histfit|hmm(?:decode|estimate|generate|train|viterbi)|hougen|hyge(?:cdf|inv|pdf|rnd|stat)|icdf|inconsistent|interactionplot|invpred|iqr|iwishrnd|jackknife|jbtest|johnsrnd|KDTreeSearcher|kmeans|knnsearch|kruskalwallis|ksdensity|kstest|kstest2|kurtosis|lasso|lassoglm|lassoPlot|leverage|lhsdesign|lhsnorm|lillietest|LinearModel(?:.fit)?|linhyptest|linkage|logn(?:cdf|fit|inv|like|pdf|rnd|stat)|lsline|mad|mahal|maineffectsplot|manova1|manovacluster|mdscale|mhsample|mle|mlecov|mnpdf|mnrfit|mnrnd|mnrval|moment|multcompare|multivarichart|mvn(?:cdf|pdf|rnd)|mvregress|mvregresslike|mvt(?:cdf|pdf|rnd)|NaiveBayes(?:.fit)?|nan(?:cov|max|mean|median|min|std|sum|var)|nbin(?:cdf|fit|inv|pdf|rnd|stat)|ncf(?:cdf|inv|pdf|rnd|stat)|nct(?:cdf|inv|pdf|rnd|stat)|ncx2(?:cdf|inv|pdf|rnd|stat)|NeighborSearcher|nlinfit|nlintool|nlmefit|nlmefitsa|nlparci|nlpredci|nnmf|nominal|NonLinearModel(?:.fit)?|norm(?:cdf|fit|inv|like|pdf|rnd|stat)|normplot|normspec|ordinal|outlierMeasure|parallelcoords|paretotails|partialcorr|pcacov|pcares|pdf|pdist|pdist2|pearsrnd|perfcurve|perms|piecewisedistribution|plsregress|poiss(?:cdf|fit|inv|pdf|rnd|tat)|polyconf|polytool|prctile|princomp|ProbDist(?:Kernel|Parametric|UnivKernel|UnivParam)?|probplot|procrustes|qqplot|qrandset|qrandstream|quantile|randg|random|randsample|randtool|range|rangesearch|ranksum|rayl(?:cdf|fit|inv|pdf|rnd|stat)|rcoplot|refcurve|refline|regress|Regression(?:BaggedEnsemble|Ensemble|PartitionedEnsemble|PartitionedModel|Tree(?:.(?:fit|template))?)|regstats|relieff|ridge|robustdemo|robustfit|rotatefactors|rowexch|rsmdemo|rstool|runstest|sampsizepwr|scatterhist|sequentialfs|signrank|signtest|silhouette|skewness|slicesample|sobolset|squareform|statget|statset|stepwise|stepwisefit|surfht|tabulate|tblread|tblwrite|tcdf|tdfread|tiedrank|tinv|tpdf|TreeBagger|treedisp|treefit|treeprune|treetest|treeval|trimmean|trnd|tstat|ttest|ttest2|unid(?:cdf|inv|pdf|rnd|stat)|unif(?:cdf|inv|it|pdf|rnd|stat)|vartest(?:2|n)?|wbl(?:cdf|fit|inv|like|pdf|rnd|stat)|wblplot|wishrnd|x2fx|xptread|zscore|ztest)\b/,
-a],["fun_tbx",/^\b(?:adapthisteq|analyze75info|analyze75read|applycform|applylut|axes2pix|bestblk|blockproc|bwarea|bwareaopen|bwboundaries|bwconncomp|bwconvhull|bwdist|bwdistgeodesic|bweuler|bwhitmiss|bwlabel|bwlabeln|bwmorph|bwpack|bwperim|bwselect|bwtraceboundary|bwulterode|bwunpack|checkerboard|col2im|colfilt|conndef|convmtx2|corner|cornermetric|corr2|cp2tform|cpcorr|cpselect|cpstruct2pairs|dct2|dctmtx|deconvblind|deconvlucy|deconvreg|deconvwnr|decorrstretch|demosaic|dicom(?:anon|dict|info|lookup|read|uid|write)|edge|edgetaper|entropy|entropyfilt|fan2para|fanbeam|findbounds|fliptform|freqz2|fsamp2|fspecial|ftrans2|fwind1|fwind2|getheight|getimage|getimagemodel|getline|getneighbors|getnhood|getpts|getrangefromclass|getrect|getsequence|gray2ind|graycomatrix|graycoprops|graydist|grayslice|graythresh|hdrread|hdrwrite|histeq|hough|houghlines|houghpeaks|iccfind|iccread|iccroot|iccwrite|idct2|ifanbeam|im2bw|im2col|im2double|im2int16|im2java2d|im2single|im2uint16|im2uint8|imabsdiff|imadd|imadjust|ImageAdapter|imageinfo|imagemodel|imapplymatrix|imattributes|imbothat|imclearborder|imclose|imcolormaptool|imcomplement|imcontour|imcontrast|imcrop|imdilate|imdisplayrange|imdistline|imdivide|imellipse|imerode|imextendedmax|imextendedmin|imfill|imfilter|imfindcircles|imfreehand|imfuse|imgca|imgcf|imgetfile|imhandles|imhist|imhmax|imhmin|imimposemin|imlincomb|imline|immagbox|immovie|immultiply|imnoise|imopen|imoverview|imoverviewpanel|impixel|impixelinfo|impixelinfoval|impixelregion|impixelregionpanel|implay|impoint|impoly|impositionrect|improfile|imputfile|impyramid|imreconstruct|imrect|imregconfig|imregionalmax|imregionalmin|imregister|imresize|imroi|imrotate|imsave|imscrollpanel|imshow|imshowpair|imsubtract|imtool|imtophat|imtransform|imview|ind2gray|ind2rgb|interfileinfo|interfileread|intlut|ippl|iptaddcallback|iptcheckconn|iptcheckhandle|iptcheckinput|iptcheckmap|iptchecknargin|iptcheckstrs|iptdemos|iptgetapi|iptGetPointerBehavior|iptgetpref|ipticondir|iptnum2ordinal|iptPointerManager|iptprefs|iptremovecallback|iptSetPointerBehavior|iptsetpref|iptwindowalign|iradon|isbw|isflat|isgray|isicc|isind|isnitf|isrgb|isrset|lab2double|lab2uint16|lab2uint8|label2rgb|labelmatrix|makecform|makeConstrainToRectFcn|makehdr|makelut|makeresampler|maketform|mat2gray|mean2|medfilt2|montage|nitfinfo|nitfread|nlfilter|normxcorr2|ntsc2rgb|openrset|ordfilt2|otf2psf|padarray|para2fan|phantom|poly2mask|psf2otf|qtdecomp|qtgetblk|qtsetblk|radon|rangefilt|reflect|regionprops|registration.metric.(?:MattesMutualInformation|MeanSquares)|registration.optimizer.(?:OnePlusOneEvolutionary|RegularStepGradientDescent)|rgb2gray|rgb2ntsc|rgb2ycbcr|roicolor|roifill|roifilt2|roipoly|rsetwrite|std2|stdfilt|strel|stretchlim|subimage|tformarray|tformfwd|tforminv|tonemap|translate|truesize|uintlut|viscircles|warp|watershed|whitepoint|wiener2|xyz2double|xyz2uint16|ycbcr2rgb)\b/,
-a],["fun_tbx",/^\b(?:bintprog|color|fgoalattain|fminbnd|fmincon|fminimax|fminsearch|fminunc|fseminf|fsolve|fzero|fzmult|gangstr|ktrlink|linprog|lsqcurvefit|lsqlin|lsqnonlin|lsqnonneg|optimget|optimset|optimtool|quadprog)\b/,a],["ident",/^[A-Za-z]\w*(?:\.[A-Za-z]\w*)*/,a]]),["matlab-identifiers"]);b.registerLangHandler(b.createSimpleLexer([],e),["matlab-operators"]);b.registerLangHandler(b.createSimpleLexer(c,d),["matlab"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-ml.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-ml.js
deleted file mode 100644
index 8ed2b0c..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-ml.js
+++ /dev/null
@@ -1,2 +0,0 @@
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["com",/^#(?:if[\t\n\r \xa0]+(?:[$_a-z][\w']*|``[^\t\n\r`]*(?:``|$))|else|endif|light)/i,null,"#"],["str",/^(?:"(?:[^"\\]|\\[\S\s])*(?:"|$)|'(?:[^'\\]|\\[\S\s])(?:'|$))/,null,"\"'"]],[["com",/^(?:\/\/[^\n\r]*|\(\*[\S\s]*?\*\))/],["kwd",/^(?:abstract|and|as|assert|begin|class|default|delegate|do|done|downcast|downto|elif|else|end|exception|extern|false|finally|for|fun|function|if|in|inherit|inline|interface|internal|lazy|let|match|member|module|mutable|namespace|new|null|of|open|or|override|private|public|rec|return|static|struct|then|to|true|try|type|upcast|use|val|void|when|while|with|yield|asr|land|lor|lsl|lsr|lxor|mod|sig|atomic|break|checked|component|const|constraint|constructor|continue|eager|event|external|fixed|functor|global|include|method|mixin|object|parallel|process|protected|pure|sealed|trait|virtual|volatile)\b/],
-["lit",/^[+-]?(?:0x[\da-f]+|(?:\.\d+|\d+(?:\.\d*)?)(?:e[+-]?\d+)?)/i],["pln",/^(?:[_a-z][\w']*[!#?]?|``[^\t\n\r`]*(?:``|$))/i],["pun",/^[^\w\t\n\r "'\xa0]+/]]),["fs","ml"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-mumps.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-mumps.js
deleted file mode 100644
index 8a6b3fd..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-mumps.js
+++ /dev/null
@@ -1,2 +0,0 @@
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["str",/^"(?:[^"]|\\.)*"/,null,'"']],[["com",/^;[^\n\r]*/,null,";"],["dec",/^\$(?:d|device|ec|ecode|es|estack|et|etrap|h|horolog|i|io|j|job|k|key|p|principal|q|quit|st|stack|s|storage|sy|system|t|test|tl|tlevel|tr|trestart|x|y|z[a-z]*|a|ascii|c|char|d|data|e|extract|f|find|fn|fnumber|g|get|j|justify|l|length|na|name|o|order|p|piece|ql|qlength|qs|qsubscript|q|query|r|random|re|reverse|s|select|st|stack|t|text|tr|translate|nan)\b/i,
-null],["kwd",/^(?:[^$]b|break|c|close|d|do|e|else|f|for|g|goto|h|halt|h|hang|i|if|j|job|k|kill|l|lock|m|merge|n|new|o|open|q|quit|r|read|s|set|tc|tcommit|tre|trestart|tro|trollback|ts|tstart|u|use|v|view|w|write|x|xecute)\b/i,null],["lit",/^[+-]?(?:\.\d+|\d+(?:\.\d*)?)(?:e[+-]?\d+)?/i],["pln",/^[a-z][^\W_]*/i],["pun",/^[^\w\t\n\r"$%;^\xa0]|_/]]),["mumps"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-n.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-n.js
deleted file mode 100644
index 27812a5..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-n.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var a=null;
-PR.registerLangHandler(PR.createSimpleLexer([["str",/^(?:'(?:[^\n\r'\\]|\\.)*'|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,a,'"'],["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,a,"#"],["pln",/^\s+/,a," \r\n\t\u00a0"]],[["str",/^@"(?:[^"]|"")*(?:"|$)/,a],["str",/^<#[^#>]*(?:#>|$)/,a],["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,a],["com",/^\/\/[^\n\r]*/,a],["com",/^\/\*[\S\s]*?(?:\*\/|$)/,
-a],["kwd",/^(?:abstract|and|as|base|catch|class|def|delegate|enum|event|extern|false|finally|fun|implements|interface|internal|is|macro|match|matches|module|mutable|namespace|new|null|out|override|params|partial|private|protected|public|ref|sealed|static|struct|syntax|this|throw|true|try|type|typeof|using|variant|virtual|volatile|when|where|with|assert|assert2|async|break|checked|continue|do|else|ensures|for|foreach|if|late|lock|new|nolate|otherwise|regexp|repeat|requires|return|surroundwith|unchecked|unless|using|while|yield)\b/,
-a],["typ",/^(?:array|bool|byte|char|decimal|double|float|int|list|long|object|sbyte|short|string|ulong|uint|ufloat|ulong|ushort|void)\b/,a],["lit",/^@[$_a-z][\w$@]*/i,a],["typ",/^@[A-Z]+[a-z][\w$@]*/,a],["pln",/^'?[$_a-z][\w$@]*/i,a],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,a,"0123456789"],["pun",/^.[^\s\w"-$'./@`]*/,a]]),["n","nemerle"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-pascal.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-pascal.js
deleted file mode 100644
index 8435fad..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-pascal.js
+++ /dev/null
@@ -1,3 +0,0 @@
-var a=null;
-PR.registerLangHandler(PR.createSimpleLexer([["str",/^'(?:[^\n\r'\\]|\\.)*(?:'|$)/,a,"'"],["pln",/^\s+/,a," \r\n\t\u00a0"]],[["com",/^\(\*[\S\s]*?(?:\*\)|$)|^{[\S\s]*?(?:}|$)/,a],["kwd",/^(?:absolute|and|array|asm|assembler|begin|case|const|constructor|destructor|div|do|downto|else|end|external|for|forward|function|goto|if|implementation|in|inline|interface|interrupt|label|mod|not|object|of|or|packed|procedure|program|record|repeat|set|shl|shr|then|to|type|unit|until|uses|var|virtual|while|with|xor)\b/i,a],
-["lit",/^(?:true|false|self|nil)/i,a],["pln",/^[a-z][^\W_]*/i,a],["lit",/^(?:\$[\da-f]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?)/i,a,"0123456789"],["pun",/^.[^\s\w$'./@]*/,a]]),["pascal"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-proto.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-proto.js
deleted file mode 100644
index f006ad8..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-proto.js
+++ /dev/null
@@ -1 +0,0 @@
-PR.registerLangHandler(PR.sourceDecorator({keywords:"bytes,default,double,enum,extend,extensions,false,group,import,max,message,option,optional,package,repeated,required,returns,rpc,service,syntax,to,true",types:/^(bool|(double|s?fixed|[su]?int)(32|64)|float|string)\b/,cStyleComments:!0}),["proto"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-r.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-r.js
deleted file mode 100644
index 99af8f8..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-r.js
+++ /dev/null
@@ -1,2 +0,0 @@
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,null,'"'],["str",/^'(?:[^'\\]|\\[\S\s])*(?:'|$)/,null,"'"]],[["com",/^#.*/],["kwd",/^(?:if|else|for|while|repeat|in|next|break|return|switch|function)(?![\w.])/],["lit",/^0[Xx][\dA-Fa-f]+([Pp]\d+)?[Li]?/],["lit",/^[+-]?(\d+(\.\d+)?|\.\d+)([Ee][+-]?\d+)?[Li]?/],["lit",/^(?:NULL|NA(?:_(?:integer|real|complex|character)_)?|Inf|TRUE|FALSE|NaN|\.\.(?:\.|\d+))(?![\w.])/],
-["pun",/^(?:<<?-|->>?|-|==|<=|>=|<|>|&&?|!=|\|\|?|[!*+/^]|%.*?%|[$=@~]|:{1,3}|[(),;?[\]{}])/],["pln",/^(?:[A-Za-z]+[\w.]*|\.[^\W\d][\w.]*)(?![\w.])/],["str",/^`.+`/]]),["r","s","R","S","Splus"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-rd.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-rd.js
deleted file mode 100644
index 7a7e43f..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-rd.js
+++ /dev/null
@@ -1 +0,0 @@
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["com",/^%[^\n\r]*/,null,"%"]],[["lit",/^\\(?:cr|l?dots|R|tab)\b/],["kwd",/^\\[@-Za-z]+/],["kwd",/^#(?:ifn?def|endif)/],["pln",/^\\[{}]/],["pun",/^[()[\]{}]+/]]),["Rd","rd"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-scala.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-scala.js
deleted file mode 100644
index 3f97dba..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-scala.js
+++ /dev/null
@@ -1,2 +0,0 @@
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["str",/^"(?:""(?:""?(?!")|[^"\\]|\\.)*"{0,3}|(?:[^\n\r"\\]|\\.)*"?)/,null,'"'],["lit",/^`(?:[^\n\r\\`]|\\.)*`?/,null,"`"],["pun",/^[!#%&(--:-@[-^{-~]+/,null,"!#%&()*+,-:;<=>?@[\\]^{|}~"]],[["str",/^'(?:[^\n\r'\\]|\\(?:'|[^\n\r']+))'/],["lit",/^'[$A-Z_a-z][\w$]*(?![\w$'])/],["kwd",/^(?:abstract|case|catch|class|def|do|else|extends|final|finally|for|forSome|if|implicit|import|lazy|match|new|object|override|package|private|protected|requires|return|sealed|super|throw|trait|try|type|val|var|while|with|yield)\b/],
-["lit",/^(?:true|false|null|this)\b/],["lit",/^(?:0(?:[0-7]+|x[\da-f]+)l?|(?:0|[1-9]\d*)(?:(?:\.\d+)?(?:e[+-]?\d+)?f?|l?)|\\.\d+(?:e[+-]?\d+)?f?)/i],["typ",/^[$_]*[A-Z][\d$A-Z_]*[a-z][\w$]*/],["pln",/^[$A-Z_a-z][\w$]*/],["com",/^\/(?:\/.*|\*(?:\/|\**[^*/])*(?:\*+\/?)?)/],["pun",/^(?:\.+|\/)/]]),["scala"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-sql.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-sql.js
deleted file mode 100644
index 8ec4280..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-sql.js
+++ /dev/null
@@ -1,2 +0,0 @@
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["str",/^(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')/,null,"\"'"]],[["com",/^(?:--[^\n\r]*|\/\*[\S\s]*?(?:\*\/|$))/],["kwd",/^(?:add|all|alter|and|any|apply|as|asc|authorization|backup|begin|between|break|browse|bulk|by|cascade|case|check|checkpoint|close|clustered|coalesce|collate|column|commit|compute|connect|constraint|contains|containstable|continue|convert|create|cross|current|current_date|current_time|current_timestamp|current_user|cursor|database|dbcc|deallocate|declare|default|delete|deny|desc|disk|distinct|distributed|double|drop|dummy|dump|else|end|errlvl|escape|except|exec|execute|exists|exit|fetch|file|fillfactor|following|for|foreign|freetext|freetexttable|from|full|function|goto|grant|group|having|holdlock|identity|identitycol|identity_insert|if|in|index|inner|insert|intersect|into|is|join|key|kill|left|like|lineno|load|match|matched|merge|natural|national|nocheck|nonclustered|nocycle|not|null|nullif|of|off|offsets|on|open|opendatasource|openquery|openrowset|openxml|option|or|order|outer|over|partition|percent|pivot|plan|preceding|precision|primary|print|proc|procedure|public|raiserror|read|readtext|reconfigure|references|replication|restore|restrict|return|revoke|right|rollback|rowcount|rowguidcol|rows?|rule|save|schema|select|session_user|set|setuser|shutdown|some|start|statistics|system_user|table|textsize|then|to|top|tran|transaction|trigger|truncate|tsequal|unbounded|union|unique|unpivot|update|updatetext|use|user|using|values|varying|view|waitfor|when|where|while|with|within|writetext|xml)(?=[^\w-]|$)/i,
-null],["lit",/^[+-]?(?:0x[\da-f]+|(?:\.\d+|\d+(?:\.\d*)?)(?:e[+-]?\d+)?)/i],["pln",/^[_a-z][\w-]*/i],["pun",/^[^\w\t\n\r "'\xa0][^\w\t\n\r "'+\xa0-]*/]]),["sql"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-tcl.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-tcl.js
deleted file mode 100644
index 490f562..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-tcl.js
+++ /dev/null
@@ -1,3 +0,0 @@
-var a=null;
-PR.registerLangHandler(PR.createSimpleLexer([["opn",/^{+/,a,"{"],["clo",/^}+/,a,"}"],["com",/^#[^\n\r]*/,a,"#"],["pln",/^[\t\n\r \xa0]+/,a,"\t\n\r \u00a0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,a,'"']],[["kwd",/^(?:after|append|apply|array|break|case|catch|continue|error|eval|exec|exit|expr|for|foreach|if|incr|info|proc|return|set|switch|trace|uplevel|upvar|while)\b/,a],["lit",/^[+-]?(?:[#0]x[\da-f]+|\d+\/\d+|(?:\.\d+|\d+(?:\.\d*)?)(?:[de][+-]?\d+)?)/i],["lit",
-/^'(?:-*(?:\w|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?)?/],["pln",/^-*(?:[_a-z]|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?/i],["pun",/^[^\w\t\n\r "'-);\\\xa0]+/]]),["tcl"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-tex.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-tex.js
deleted file mode 100644
index dcfdadd..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-tex.js
+++ /dev/null
@@ -1 +0,0 @@
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["com",/^%[^\n\r]*/,null,"%"]],[["kwd",/^\\[@-Za-z]+/],["kwd",/^\\./],["typ",/^[$&]/],["lit",/[+-]?(?:\.\d+|\d+(?:\.\d*)?)(cm|em|ex|in|pc|pt|bp|mm)/i],["pun",/^[()=[\]{}]+/]]),["latex","tex"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-vb.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-vb.js
deleted file mode 100644
index ddde464..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-vb.js
+++ /dev/null
@@ -1,2 +0,0 @@
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0\u2028\u2029]+/,null,"\t\n\r \u00a0\u2028\u2029"],["str",/^(?:["\u201c\u201d](?:[^"\u201c\u201d]|["\u201c\u201d]{2})(?:["\u201c\u201d]c|$)|["\u201c\u201d](?:[^"\u201c\u201d]|["\u201c\u201d]{2})*(?:["\u201c\u201d]|$))/i,null,'"\u201c\u201d'],["com",/^['\u2018\u2019](?:_(?:\r\n?|[^\r]?)|[^\n\r_\u2028\u2029])*/,null,"'\u2018\u2019"]],[["kwd",/^(?:addhandler|addressof|alias|and|andalso|ansi|as|assembly|auto|boolean|byref|byte|byval|call|case|catch|cbool|cbyte|cchar|cdate|cdbl|cdec|char|cint|class|clng|cobj|const|cshort|csng|cstr|ctype|date|decimal|declare|default|delegate|dim|directcast|do|double|each|else|elseif|end|endif|enum|erase|error|event|exit|finally|for|friend|function|get|gettype|gosub|goto|handles|if|implements|imports|in|inherits|integer|interface|is|let|lib|like|long|loop|me|mod|module|mustinherit|mustoverride|mybase|myclass|namespace|new|next|not|notinheritable|notoverridable|object|on|option|optional|or|orelse|overloads|overridable|overrides|paramarray|preserve|private|property|protected|public|raiseevent|readonly|redim|removehandler|resume|return|select|set|shadows|shared|short|single|static|step|stop|string|structure|sub|synclock|then|throw|to|try|typeof|unicode|until|variant|wend|when|while|with|withevents|writeonly|xor|endif|gosub|let|variant|wend)\b/i,
-null],["com",/^rem\b.*/i],["lit",/^(?:true\b|false\b|nothing\b|\d+(?:e[+-]?\d+[dfr]?|[dfilrs])?|(?:&h[\da-f]+|&o[0-7]+)[ils]?|\d*\.\d+(?:e[+-]?\d+)?[dfr]?|#\s+(?:\d+[/-]\d+[/-]\d+(?:\s+\d+:\d+(?::\d+)?(\s*(?:am|pm))?)?|\d+:\d+(?::\d+)?(\s*(?:am|pm))?)\s+#)/i],["pln",/^(?:(?:[a-z]|_\w)\w*(?:\[[!#%&@]+])?|\[(?:[a-z]|_\w)\w*])/i],["pun",/^[^\w\t\n\r "'[\]\xa0\u2018\u2019\u201c\u201d\u2028\u2029]+/],["pun",/^(?:\[|])/]]),["vb","vbs"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-vhdl.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-vhdl.js
deleted file mode 100644
index 51f3017..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-vhdl.js
+++ /dev/null
@@ -1,3 +0,0 @@
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"]],[["str",/^(?:[box]?"(?:[^"]|"")*"|'.')/i],["com",/^--[^\n\r]*/],["kwd",/^(?:abs|access|after|alias|all|and|architecture|array|assert|attribute|begin|block|body|buffer|bus|case|component|configuration|constant|disconnect|downto|else|elsif|end|entity|exit|file|for|function|generate|generic|group|guarded|if|impure|in|inertial|inout|is|label|library|linkage|literal|loop|map|mod|nand|new|next|nor|not|null|of|on|open|or|others|out|package|port|postponed|procedure|process|pure|range|record|register|reject|rem|report|return|rol|ror|select|severity|shared|signal|sla|sll|sra|srl|subtype|then|to|transport|type|unaffected|units|until|use|variable|wait|when|while|with|xnor|xor)(?=[^\w-]|$)/i,
-null],["typ",/^(?:bit|bit_vector|character|boolean|integer|real|time|string|severity_level|positive|natural|signed|unsigned|line|text|std_u?logic(?:_vector)?)(?=[^\w-]|$)/i,null],["typ",/^'(?:active|ascending|base|delayed|driving|driving_value|event|high|image|instance_name|last_active|last_event|last_value|left|leftof|length|low|path_name|pos|pred|quiet|range|reverse_range|right|rightof|simple_name|stable|succ|transaction|val|value)(?=[^\w-]|$)/i,null],["lit",/^\d+(?:_\d+)*(?:#[\w.\\]+#(?:[+-]?\d+(?:_\d+)*)?|(?:\.\d+(?:_\d+)*)?(?:e[+-]?\d+(?:_\d+)*)?)/i],
-["pln",/^(?:[a-z]\w*|\\[^\\]*\\)/i],["pun",/^[^\w\t\n\r "'\xa0][^\w\t\n\r "'\xa0-]*/]]),["vhdl","vhd"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-wiki.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-wiki.js
deleted file mode 100644
index 96c1e34..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-wiki.js
+++ /dev/null
@@ -1,2 +0,0 @@
-PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\d\t a-gi-z\xa0]+/,null,"\t \u00a0abcdefgijklmnopqrstuvwxyz0123456789"],["pun",/^[*=[\]^~]+/,null,"=*~^[]"]],[["lang-wiki.meta",/(?:^^|\r\n?|\n)(#[a-z]+)\b/],["lit",/^[A-Z][a-z][\da-z]+[A-Z][a-z][^\W_]+\b/],["lang-",/^{{{([\S\s]+?)}}}/],["lang-",/^`([^\n\r`]+)`/],["str",/^https?:\/\/[^\s#/?]*(?:\/[^\s#?]*)?(?:\?[^\s#]*)?(?:#\S*)?/i],["pln",/^(?:\r\n|[\S\s])[^\n\r#*=A-[^`h{~]*/]]),["wiki"]);
-PR.registerLangHandler(PR.createSimpleLexer([["kwd",/^#[a-z]+/i,null,"#"]],[]),["wiki.meta"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-xq.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-xq.js
deleted file mode 100644
index e323ae3..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-xq.js
+++ /dev/null
@@ -1,3 +0,0 @@
-PR.registerLangHandler(PR.createSimpleLexer([["var pln",/^\$[\w-]+/,null,"$"]],[["pln",/^[\s=][<>][\s=]/],["lit",/^@[\w-]+/],["tag",/^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["com",/^\(:[\S\s]*?:\)/],["pln",/^[(),/;[\]{}]$/],["str",/^(?:"(?:[^"\\{]|\\[\S\s])*(?:"|$)|'(?:[^'\\{]|\\[\S\s])*(?:'|$))/,null,"\"'"],["kwd",/^(?:xquery|where|version|variable|union|typeswitch|treat|to|then|text|stable|sortby|some|self|schema|satisfies|returns|return|ref|processing-instruction|preceding-sibling|preceding|precedes|parent|only|of|node|namespace|module|let|item|intersect|instance|in|import|if|function|for|follows|following-sibling|following|external|except|every|else|element|descending|descendant-or-self|descendant|define|default|declare|comment|child|cast|case|before|attribute|assert|ascending|as|ancestor-or-self|ancestor|after|eq|order|by|or|and|schema-element|document-node|node|at)\b/],
-["typ",/^(?:xs:yearMonthDuration|xs:unsignedLong|xs:time|xs:string|xs:short|xs:QName|xs:Name|xs:long|xs:integer|xs:int|xs:gYearMonth|xs:gYear|xs:gMonthDay|xs:gDay|xs:float|xs:duration|xs:double|xs:decimal|xs:dayTimeDuration|xs:dateTime|xs:date|xs:byte|xs:boolean|xs:anyURI|xf:yearMonthDuration)\b/,null],["fun pln",/^(?:xp:dereference|xinc:node-expand|xinc:link-references|xinc:link-expand|xhtml:restructure|xhtml:clean|xhtml:add-lists|xdmp:zip-manifest|xdmp:zip-get|xdmp:zip-create|xdmp:xquery-version|xdmp:word-convert|xdmp:with-namespaces|xdmp:version|xdmp:value|xdmp:user-roles|xdmp:user-last-login|xdmp:user|xdmp:url-encode|xdmp:url-decode|xdmp:uri-is-file|xdmp:uri-format|xdmp:uri-content-type|xdmp:unquote|xdmp:unpath|xdmp:triggers-database|xdmp:trace|xdmp:to-json|xdmp:tidy|xdmp:subbinary|xdmp:strftime|xdmp:spawn-in|xdmp:spawn|xdmp:sleep|xdmp:shutdown|xdmp:set-session-field|xdmp:set-response-encoding|xdmp:set-response-content-type|xdmp:set-response-code|xdmp:set-request-time-limit|xdmp:set|xdmp:servers|xdmp:server-status|xdmp:server-name|xdmp:server|xdmp:security-database|xdmp:security-assert|xdmp:schema-database|xdmp:save|xdmp:role-roles|xdmp:role|xdmp:rethrow|xdmp:restart|xdmp:request-timestamp|xdmp:request-status|xdmp:request-cancel|xdmp:request|xdmp:redirect-response|xdmp:random|xdmp:quote|xdmp:query-trace|xdmp:query-meters|xdmp:product-edition|xdmp:privilege-roles|xdmp:privilege|xdmp:pretty-print|xdmp:powerpoint-convert|xdmp:platform|xdmp:permission|xdmp:pdf-convert|xdmp:path|xdmp:octal-to-integer|xdmp:node-uri|xdmp:node-replace|xdmp:node-kind|xdmp:node-insert-child|xdmp:node-insert-before|xdmp:node-insert-after|xdmp:node-delete|xdmp:node-database|xdmp:mul64|xdmp:modules-root|xdmp:modules-database|xdmp:merging|xdmp:merge-cancel|xdmp:merge|xdmp:md5|xdmp:logout|xdmp:login|xdmp:log-level|xdmp:log|xdmp:lock-release|xdmp:lock-acquire|xdmp:load|xdmp:invoke-in|xdmp:invoke|xdmp:integer-to-octal|xdmp:integer-to-hex|xdmp:http-put|xdmp:http-post|xdmp:http-options|xdmp:http-head|xdmp:http-get|xdmp:http-delete|xdmp:hosts|xdmp:host-status|xdmp:host-name|xdmp:host|xdmp:hex-to-integer|xdmp:hash64|xdmp:hash32|xdmp:has-privilege|xdmp:groups|xdmp:group-serves|xdmp:group-servers|xdmp:group-name|xdmp:group-hosts|xdmp:group|xdmp:get-session-field-names|xdmp:get-session-field|xdmp:get-response-encoding|xdmp:get-response-code|xdmp:get-request-username|xdmp:get-request-user|xdmp:get-request-url|xdmp:get-request-protocol|xdmp:get-request-path|xdmp:get-request-method|xdmp:get-request-header-names|xdmp:get-request-header|xdmp:get-request-field-names|xdmp:get-request-field-filename|xdmp:get-request-field-content-type|xdmp:get-request-field|xdmp:get-request-client-certificate|xdmp:get-request-client-address|xdmp:get-request-body|xdmp:get-current-user|xdmp:get-current-roles|xdmp:get|xdmp:function-name|xdmp:function-module|xdmp:function|xdmp:from-json|xdmp:forests|xdmp:forest-status|xdmp:forest-restore|xdmp:forest-restart|xdmp:forest-name|xdmp:forest-delete|xdmp:forest-databases|xdmp:forest-counts|xdmp:forest-clear|xdmp:forest-backup|xdmp:forest|xdmp:filesystem-file|xdmp:filesystem-directory|xdmp:exists|xdmp:excel-convert|xdmp:eval-in|xdmp:eval|xdmp:estimate|xdmp:email|xdmp:element-content-type|xdmp:elapsed-time|xdmp:document-set-quality|xdmp:document-set-property|xdmp:document-set-properties|xdmp:document-set-permissions|xdmp:document-set-collections|xdmp:document-remove-properties|xdmp:document-remove-permissions|xdmp:document-remove-collections|xdmp:document-properties|xdmp:document-locks|xdmp:document-load|xdmp:document-insert|xdmp:document-get-quality|xdmp:document-get-properties|xdmp:document-get-permissions|xdmp:document-get-collections|xdmp:document-get|xdmp:document-forest|xdmp:document-delete|xdmp:document-add-properties|xdmp:document-add-permissions|xdmp:document-add-collections|xdmp:directory-properties|xdmp:directory-locks|xdmp:directory-delete|xdmp:directory-create|xdmp:directory|xdmp:diacritic-less|xdmp:describe|xdmp:default-permissions|xdmp:default-collections|xdmp:databases|xdmp:database-restore-validate|xdmp:database-restore-status|xdmp:database-restore-cancel|xdmp:database-restore|xdmp:database-name|xdmp:database-forests|xdmp:database-backup-validate|xdmp:database-backup-status|xdmp:database-backup-purge|xdmp:database-backup-cancel|xdmp:database-backup|xdmp:database|xdmp:collection-properties|xdmp:collection-locks|xdmp:collection-delete|xdmp:collation-canonical-uri|xdmp:castable-as|xdmp:can-grant-roles|xdmp:base64-encode|xdmp:base64-decode|xdmp:architecture|xdmp:apply|xdmp:amp-roles|xdmp:amp|xdmp:add64|xdmp:add-response-header|xdmp:access|trgr:trigger-set-recursive|trgr:trigger-set-permissions|trgr:trigger-set-name|trgr:trigger-set-module|trgr:trigger-set-event|trgr:trigger-set-description|trgr:trigger-remove-permissions|trgr:trigger-module|trgr:trigger-get-permissions|trgr:trigger-enable|trgr:trigger-disable|trgr:trigger-database-online-event|trgr:trigger-data-event|trgr:trigger-add-permissions|trgr:remove-trigger|trgr:property-content|trgr:pre-commit|trgr:post-commit|trgr:get-trigger-by-id|trgr:get-trigger|trgr:document-scope|trgr:document-content|trgr:directory-scope|trgr:create-trigger|trgr:collection-scope|trgr:any-property-content|thsr:set-entry|thsr:remove-term|thsr:remove-synonym|thsr:remove-entry|thsr:query-lookup|thsr:lookup|thsr:load|thsr:insert|thsr:expand|thsr:add-synonym|spell:suggest-detailed|spell:suggest|spell:remove-word|spell:make-dictionary|spell:load|spell:levenshtein-distance|spell:is-correct|spell:insert|spell:double-metaphone|spell:add-word|sec:users-collection|sec:user-set-roles|sec:user-set-password|sec:user-set-name|sec:user-set-description|sec:user-set-default-permissions|sec:user-set-default-collections|sec:user-remove-roles|sec:user-privileges|sec:user-get-roles|sec:user-get-description|sec:user-get-default-permissions|sec:user-get-default-collections|sec:user-doc-permissions|sec:user-doc-collections|sec:user-add-roles|sec:unprotect-collection|sec:uid-for-name|sec:set-realm|sec:security-version|sec:security-namespace|sec:security-installed|sec:security-collection|sec:roles-collection|sec:role-set-roles|sec:role-set-name|sec:role-set-description|sec:role-set-default-permissions|sec:role-set-default-collections|sec:role-remove-roles|sec:role-privileges|sec:role-get-roles|sec:role-get-description|sec:role-get-default-permissions|sec:role-get-default-collections|sec:role-doc-permissions|sec:role-doc-collections|sec:role-add-roles|sec:remove-user|sec:remove-role-from-users|sec:remove-role-from-role|sec:remove-role-from-privileges|sec:remove-role-from-amps|sec:remove-role|sec:remove-privilege|sec:remove-amp|sec:protect-collection|sec:privileges-collection|sec:privilege-set-roles|sec:privilege-set-name|sec:privilege-remove-roles|sec:privilege-get-roles|sec:privilege-add-roles|sec:priv-doc-permissions|sec:priv-doc-collections|sec:get-user-names|sec:get-unique-elem-id|sec:get-role-names|sec:get-role-ids|sec:get-privilege|sec:get-distinct-permissions|sec:get-collection|sec:get-amp|sec:create-user-with-role|sec:create-user|sec:create-role|sec:create-privilege|sec:create-amp|sec:collections-collection|sec:collection-set-permissions|sec:collection-remove-permissions|sec:collection-get-permissions|sec:collection-add-permissions|sec:check-admin|sec:amps-collection|sec:amp-set-roles|sec:amp-remove-roles|sec:amp-get-roles|sec:amp-doc-permissions|sec:amp-doc-collections|sec:amp-add-roles|search:unparse|search:suggest|search:snippet|search:search|search:resolve-nodes|search:resolve|search:remove-constraint|search:parse|search:get-default-options|search:estimate|search:check-options|prof:value|prof:reset|prof:report|prof:invoke|prof:eval|prof:enable|prof:disable|prof:allowed|ppt:clean|pki:template-set-request|pki:template-set-name|pki:template-set-key-type|pki:template-set-key-options|pki:template-set-description|pki:template-in-use|pki:template-get-version|pki:template-get-request|pki:template-get-name|pki:template-get-key-type|pki:template-get-key-options|pki:template-get-id|pki:template-get-description|pki:need-certificate|pki:is-temporary|pki:insert-trusted-certificates|pki:insert-template|pki:insert-signed-certificates|pki:insert-certificate-revocation-list|pki:get-trusted-certificate-ids|pki:get-template-ids|pki:get-template-certificate-authority|pki:get-template-by-name|pki:get-template|pki:get-pending-certificate-requests-xml|pki:get-pending-certificate-requests-pem|pki:get-pending-certificate-request|pki:get-certificates-for-template-xml|pki:get-certificates-for-template|pki:get-certificates|pki:get-certificate-xml|pki:get-certificate-pem|pki:get-certificate|pki:generate-temporary-certificate-if-necessary|pki:generate-temporary-certificate|pki:generate-template-certificate-authority|pki:generate-certificate-request|pki:delete-template|pki:delete-certificate|pki:create-template|pdf:make-toc|pdf:insert-toc-headers|pdf:get-toc|pdf:clean|p:status-transition|p:state-transition|p:remove|p:pipelines|p:insert|p:get-by-id|p:get|p:execute|p:create|p:condition|p:collection|p:action|ooxml:runs-merge|ooxml:package-uris|ooxml:package-parts-insert|ooxml:package-parts|msword:clean|mcgm:polygon|mcgm:point|mcgm:geospatial-query-from-elements|mcgm:geospatial-query|mcgm:circle|math:tanh|math:tan|math:sqrt|math:sinh|math:sin|math:pow|math:modf|math:log10|math:log|math:ldexp|math:frexp|math:fmod|math:floor|math:fabs|math:exp|math:cosh|math:cos|math:ceil|math:atan2|math:atan|math:asin|math:acos|map:put|map:map|map:keys|map:get|map:delete|map:count|map:clear|lnk:to|lnk:remove|lnk:insert|lnk:get|lnk:from|lnk:create|kml:polygon|kml:point|kml:interior-polygon|kml:geospatial-query-from-elements|kml:geospatial-query|kml:circle|kml:box|gml:polygon|gml:point|gml:interior-polygon|gml:geospatial-query-from-elements|gml:geospatial-query|gml:circle|gml:box|georss:point|georss:geospatial-query|georss:circle|geo:polygon|geo:point|geo:interior-polygon|geo:geospatial-query-from-elements|geo:geospatial-query|geo:circle|geo:box|fn:zero-or-one|fn:years-from-duration|fn:year-from-dateTime|fn:year-from-date|fn:upper-case|fn:unordered|fn:true|fn:translate|fn:trace|fn:tokenize|fn:timezone-from-time|fn:timezone-from-dateTime|fn:timezone-from-date|fn:sum|fn:subtract-dateTimes-yielding-yearMonthDuration|fn:subtract-dateTimes-yielding-dayTimeDuration|fn:substring-before|fn:substring-after|fn:substring|fn:subsequence|fn:string-to-codepoints|fn:string-pad|fn:string-length|fn:string-join|fn:string|fn:static-base-uri|fn:starts-with|fn:seconds-from-time|fn:seconds-from-duration|fn:seconds-from-dateTime|fn:round-half-to-even|fn:round|fn:root|fn:reverse|fn:resolve-uri|fn:resolve-QName|fn:replace|fn:remove|fn:QName|fn:prefix-from-QName|fn:position|fn:one-or-more|fn:number|fn:not|fn:normalize-unicode|fn:normalize-space|fn:node-name|fn:node-kind|fn:nilled|fn:namespace-uri-from-QName|fn:namespace-uri-for-prefix|fn:namespace-uri|fn:name|fn:months-from-duration|fn:month-from-dateTime|fn:month-from-date|fn:minutes-from-time|fn:minutes-from-duration|fn:minutes-from-dateTime|fn:min|fn:max|fn:matches|fn:lower-case|fn:local-name-from-QName|fn:local-name|fn:last|fn:lang|fn:iri-to-uri|fn:insert-before|fn:index-of|fn:in-scope-prefixes|fn:implicit-timezone|fn:idref|fn:id|fn:hours-from-time|fn:hours-from-duration|fn:hours-from-dateTime|fn:floor|fn:false|fn:expanded-QName|fn:exists|fn:exactly-one|fn:escape-uri|fn:escape-html-uri|fn:error|fn:ends-with|fn:encode-for-uri|fn:empty|fn:document-uri|fn:doc-available|fn:doc|fn:distinct-values|fn:distinct-nodes|fn:default-collation|fn:deep-equal|fn:days-from-duration|fn:day-from-dateTime|fn:day-from-date|fn:data|fn:current-time|fn:current-dateTime|fn:current-date|fn:count|fn:contains|fn:concat|fn:compare|fn:collection|fn:codepoints-to-string|fn:codepoint-equal|fn:ceiling|fn:boolean|fn:base-uri|fn:avg|fn:adjust-time-to-timezone|fn:adjust-dateTime-to-timezone|fn:adjust-date-to-timezone|fn:abs|feed:unsubscribe|feed:subscription|feed:subscribe|feed:request|feed:item|feed:description|excel:clean|entity:enrich|dom:set-pipelines|dom:set-permissions|dom:set-name|dom:set-evaluation-context|dom:set-domain-scope|dom:set-description|dom:remove-pipeline|dom:remove-permissions|dom:remove|dom:get|dom:evaluation-context|dom:domains|dom:domain-scope|dom:create|dom:configuration-set-restart-user|dom:configuration-set-permissions|dom:configuration-set-evaluation-context|dom:configuration-set-default-domain|dom:configuration-get|dom:configuration-create|dom:collection|dom:add-pipeline|dom:add-permissions|dls:retention-rules|dls:retention-rule-remove|dls:retention-rule-insert|dls:retention-rule|dls:purge|dls:node-expand|dls:link-references|dls:link-expand|dls:documents-query|dls:document-versions-query|dls:document-version-uri|dls:document-version-query|dls:document-version-delete|dls:document-version-as-of|dls:document-version|dls:document-update|dls:document-unmanage|dls:document-set-quality|dls:document-set-property|dls:document-set-properties|dls:document-set-permissions|dls:document-set-collections|dls:document-retention-rules|dls:document-remove-properties|dls:document-remove-permissions|dls:document-remove-collections|dls:document-purge|dls:document-manage|dls:document-is-managed|dls:document-insert-and-manage|dls:document-include-query|dls:document-history|dls:document-get-permissions|dls:document-extract-part|dls:document-delete|dls:document-checkout-status|dls:document-checkout|dls:document-checkin|dls:document-add-properties|dls:document-add-permissions|dls:document-add-collections|dls:break-checkout|dls:author-query|dls:as-of-query|dbk:convert|dbg:wait|dbg:value|dbg:stopped|dbg:stop|dbg:step|dbg:status|dbg:stack|dbg:out|dbg:next|dbg:line|dbg:invoke|dbg:function|dbg:finish|dbg:expr|dbg:eval|dbg:disconnect|dbg:detach|dbg:continue|dbg:connect|dbg:clear|dbg:breakpoints|dbg:break|dbg:attached|dbg:attach|cvt:save-converted-documents|cvt:part-uri|cvt:destination-uri|cvt:basepath|cvt:basename|cts:words|cts:word-query-weight|cts:word-query-text|cts:word-query-options|cts:word-query|cts:word-match|cts:walk|cts:uris|cts:uri-match|cts:train|cts:tokenize|cts:thresholds|cts:stem|cts:similar-query-weight|cts:similar-query-nodes|cts:similar-query|cts:shortest-distance|cts:search|cts:score|cts:reverse-query-weight|cts:reverse-query-nodes|cts:reverse-query|cts:remainder|cts:registered-query-weight|cts:registered-query-options|cts:registered-query-ids|cts:registered-query|cts:register|cts:query|cts:quality|cts:properties-query-query|cts:properties-query|cts:polygon-vertices|cts:polygon|cts:point-longitude|cts:point-latitude|cts:point|cts:or-query-queries|cts:or-query|cts:not-query-weight|cts:not-query-query|cts:not-query|cts:near-query-weight|cts:near-query-queries|cts:near-query-options|cts:near-query-distance|cts:near-query|cts:highlight|cts:geospatial-co-occurrences|cts:frequency|cts:fitness|cts:field-words|cts:field-word-query-weight|cts:field-word-query-text|cts:field-word-query-options|cts:field-word-query-field-name|cts:field-word-query|cts:field-word-match|cts:entity-highlight|cts:element-words|cts:element-word-query-weight|cts:element-word-query-text|cts:element-word-query-options|cts:element-word-query-element-name|cts:element-word-query|cts:element-word-match|cts:element-values|cts:element-value-ranges|cts:element-value-query-weight|cts:element-value-query-text|cts:element-value-query-options|cts:element-value-query-element-name|cts:element-value-query|cts:element-value-match|cts:element-value-geospatial-co-occurrences|cts:element-value-co-occurrences|cts:element-range-query-weight|cts:element-range-query-value|cts:element-range-query-options|cts:element-range-query-operator|cts:element-range-query-element-name|cts:element-range-query|cts:element-query-query|cts:element-query-element-name|cts:element-query|cts:element-pair-geospatial-values|cts:element-pair-geospatial-value-match|cts:element-pair-geospatial-query-weight|cts:element-pair-geospatial-query-region|cts:element-pair-geospatial-query-options|cts:element-pair-geospatial-query-longitude-name|cts:element-pair-geospatial-query-latitude-name|cts:element-pair-geospatial-query-element-name|cts:element-pair-geospatial-query|cts:element-pair-geospatial-boxes|cts:element-geospatial-values|cts:element-geospatial-value-match|cts:element-geospatial-query-weight|cts:element-geospatial-query-region|cts:element-geospatial-query-options|cts:element-geospatial-query-element-name|cts:element-geospatial-query|cts:element-geospatial-boxes|cts:element-child-geospatial-values|cts:element-child-geospatial-value-match|cts:element-child-geospatial-query-weight|cts:element-child-geospatial-query-region|cts:element-child-geospatial-query-options|cts:element-child-geospatial-query-element-name|cts:element-child-geospatial-query-child-name|cts:element-child-geospatial-query|cts:element-child-geospatial-boxes|cts:element-attribute-words|cts:element-attribute-word-query-weight|cts:element-attribute-word-query-text|cts:element-attribute-word-query-options|cts:element-attribute-word-query-element-name|cts:element-attribute-word-query-attribute-name|cts:element-attribute-word-query|cts:element-attribute-word-match|cts:element-attribute-values|cts:element-attribute-value-ranges|cts:element-attribute-value-query-weight|cts:element-attribute-value-query-text|cts:element-attribute-value-query-options|cts:element-attribute-value-query-element-name|cts:element-attribute-value-query-attribute-name|cts:element-attribute-value-query|cts:element-attribute-value-match|cts:element-attribute-value-geospatial-co-occurrences|cts:element-attribute-value-co-occurrences|cts:element-attribute-range-query-weight|cts:element-attribute-range-query-value|cts:element-attribute-range-query-options|cts:element-attribute-range-query-operator|cts:element-attribute-range-query-element-name|cts:element-attribute-range-query-attribute-name|cts:element-attribute-range-query|cts:element-attribute-pair-geospatial-values|cts:element-attribute-pair-geospatial-value-match|cts:element-attribute-pair-geospatial-query-weight|cts:element-attribute-pair-geospatial-query-region|cts:element-attribute-pair-geospatial-query-options|cts:element-attribute-pair-geospatial-query-longitude-name|cts:element-attribute-pair-geospatial-query-latitude-name|cts:element-attribute-pair-geospatial-query-element-name|cts:element-attribute-pair-geospatial-query|cts:element-attribute-pair-geospatial-boxes|cts:document-query-uris|cts:document-query|cts:distance|cts:directory-query-uris|cts:directory-query-depth|cts:directory-query|cts:destination|cts:deregister|cts:contains|cts:confidence|cts:collections|cts:collection-query-uris|cts:collection-query|cts:collection-match|cts:classify|cts:circle-radius|cts:circle-center|cts:circle|cts:box-west|cts:box-south|cts:box-north|cts:box-east|cts:box|cts:bearing|cts:arc-intersection|cts:and-query-queries|cts:and-query-options|cts:and-query|cts:and-not-query-positive-query|cts:and-not-query-negative-query|cts:and-not-query|css:get|css:convert|cpf:success|cpf:failure|cpf:document-set-state|cpf:document-set-processing-status|cpf:document-set-last-updated|cpf:document-set-error|cpf:document-get-state|cpf:document-get-processing-status|cpf:document-get-last-updated|cpf:document-get-error|cpf:check-transition|alert:spawn-matching-actions|alert:rule-user-id-query|alert:rule-set-user-id|alert:rule-set-query|alert:rule-set-options|alert:rule-set-name|alert:rule-set-description|alert:rule-set-action|alert:rule-remove|alert:rule-name-query|alert:rule-insert|alert:rule-id-query|alert:rule-get-user-id|alert:rule-get-query|alert:rule-get-options|alert:rule-get-name|alert:rule-get-id|alert:rule-get-description|alert:rule-get-action|alert:rule-action-query|alert:remove-triggers|alert:make-rule|alert:make-log-action|alert:make-config|alert:make-action|alert:invoke-matching-actions|alert:get-my-rules|alert:get-all-rules|alert:get-actions|alert:find-matching-rules|alert:create-triggers|alert:config-set-uri|alert:config-set-trigger-ids|alert:config-set-options|alert:config-set-name|alert:config-set-description|alert:config-set-cpf-domain-names|alert:config-set-cpf-domain-ids|alert:config-insert|alert:config-get-uri|alert:config-get-trigger-ids|alert:config-get-options|alert:config-get-name|alert:config-get-id|alert:config-get-description|alert:config-get-cpf-domain-names|alert:config-get-cpf-domain-ids|alert:config-get|alert:config-delete|alert:action-set-options|alert:action-set-name|alert:action-set-module-root|alert:action-set-module-db|alert:action-set-module|alert:action-set-description|alert:action-remove|alert:action-insert|alert:action-get-options|alert:action-get-name|alert:action-get-module-root|alert:action-get-module-db|alert:action-get-module|alert:action-get-description|zero-or-one|years-from-duration|year-from-dateTime|year-from-date|upper-case|unordered|true|translate|trace|tokenize|timezone-from-time|timezone-from-dateTime|timezone-from-date|sum|subtract-dateTimes-yielding-yearMonthDuration|subtract-dateTimes-yielding-dayTimeDuration|substring-before|substring-after|substring|subsequence|string-to-codepoints|string-pad|string-length|string-join|string|static-base-uri|starts-with|seconds-from-time|seconds-from-duration|seconds-from-dateTime|round-half-to-even|round|root|reverse|resolve-uri|resolve-QName|replace|remove|QName|prefix-from-QName|position|one-or-more|number|not|normalize-unicode|normalize-space|node-name|node-kind|nilled|namespace-uri-from-QName|namespace-uri-for-prefix|namespace-uri|name|months-from-duration|month-from-dateTime|month-from-date|minutes-from-time|minutes-from-duration|minutes-from-dateTime|min|max|matches|lower-case|local-name-from-QName|local-name|last|lang|iri-to-uri|insert-before|index-of|in-scope-prefixes|implicit-timezone|idref|id|hours-from-time|hours-from-duration|hours-from-dateTime|floor|false|expanded-QName|exists|exactly-one|escape-uri|escape-html-uri|error|ends-with|encode-for-uri|empty|document-uri|doc-available|doc|distinct-values|distinct-nodes|default-collation|deep-equal|days-from-duration|day-from-dateTime|day-from-date|data|current-time|current-dateTime|current-date|count|contains|concat|compare|collection|codepoints-to-string|codepoint-equal|ceiling|boolean|base-uri|avg|adjust-time-to-timezone|adjust-dateTime-to-timezone|adjust-date-to-timezone|abs)\b/],
-["pln",/^[\w:-]+/],["pln",/^[\t\n\r \xa0]+/]]),["xq","xquery"]);
diff --git a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-yaml.js b/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-yaml.js
deleted file mode 100644
index c38729b..0000000
--- a/gerrit-prettify/src/main/resources/com/google/gerrit/prettify/client/lang-yaml.js
+++ /dev/null
@@ -1,2 +0,0 @@
-var a=null;
-PR.registerLangHandler(PR.createSimpleLexer([["pun",/^[:>?|]+/,a,":|>?"],["dec",/^%(?:YAML|TAG)[^\n\r#]+/,a,"%"],["typ",/^&\S+/,a,"&"],["typ",/^!\S*/,a,"!"],["str",/^"(?:[^"\\]|\\.)*(?:"|$)/,a,'"'],["str",/^'(?:[^']|'')*(?:'|$)/,a,"'"],["com",/^#[^\n\r]*/,a,"#"],["pln",/^\s+/,a," \t\r\n"]],[["dec",/^(?:---|\.\.\.)(?:[\n\r]|$)/],["pun",/^-/],["kwd",/^\w+:[\n\r ]/],["pln",/^\w+/]]),["yaml","yml"]);
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Account.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Account.java
index 327a5b8..77b0137 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Account.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Account.java
@@ -49,17 +49,13 @@
  * the internal SSH daemon. One record per SSH key uploaded by the user, keys
  * are checked in random order until a match is found.</li>
  *
- * <li>{@link StarredChange}: user has starred the change, tracking
- * notifications of updates on that change, or just book-marking it for faster
- * future reference. One record per starred change.</li>
- *
  * <li>{@link DiffPreferencesInfo}: user's preferences for rendering side-to-side
  * and unified diff</li>
  *
  * </ul>
  */
 public final class Account {
-  public static enum FieldName {
+  public enum FieldName {
     FULL_NAME, USER_NAME, REGISTER_NEW_EMAIL
   }
 
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Change.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Change.java
index 5c70d3c..26bab58 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Change.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Change.java
@@ -281,7 +281,7 @@
    * codes ('A'..'Z') indicate a change that is closed and cannot be further
    * modified.
    * */
-  public static enum Status {
+  public enum Status {
     /**
      * Change is open and pending review, or review is in progress.
      *
@@ -356,7 +356,7 @@
     private final boolean closed;
     private final ChangeStatus changeStatus;
 
-    private Status(char c, ChangeStatus cs) {
+    Status(char c, ChangeStatus cs) {
       code = c;
       closed = !(MIN_OPEN <= c && c <= MAX_OPEN);
       changeStatus = cs;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/ChangeMessage.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/ChangeMessage.java
index 70169a0..898dc94 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/ChangeMessage.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/ChangeMessage.java
@@ -74,6 +74,10 @@
   @Column(id = 5, notNull = false)
   protected PatchSet.Id patchset;
 
+  /** Tag associated with change message */
+  @Column(id = 6, notNull = false)
+  protected String tag;
+
   protected ChangeMessage() {
   }
 
@@ -117,6 +121,14 @@
     message = s;
   }
 
+  public String getTag() {
+    return tag;
+  }
+
+  public void setTag(String tag) {
+    this.tag = tag;
+  }
+
   public PatchSet.Id getPatchSetId() {
     return patchset;
   }
@@ -132,6 +144,7 @@
         + ", author=" + author
         + ", writtenOn=" + writtenOn
         + ", patchset=" + patchset
+        + ", tag=" + tag
         + ", message=[" + message
         + "]}";
   }
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Patch.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Patch.java
index 3637914..6a55965 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Patch.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Patch.java
@@ -68,7 +68,7 @@
   }
 
   /** Type of modification made to the file path. */
-  public static enum ChangeType implements CodedEnum {
+  public enum ChangeType implements CodedEnum {
     /** Path is being created/introduced by this patch. */
     ADDED('A'),
 
@@ -89,7 +89,7 @@
 
     private final char code;
 
-    private ChangeType(final char c) {
+    ChangeType(final char c) {
       code = c;
     }
 
@@ -113,7 +113,7 @@
   }
 
   /** Type of formatting for this patch. */
-  public static enum PatchType implements CodedEnum {
+  public enum PatchType implements CodedEnum {
     /**
      * A textual difference between two versions.
      *
@@ -148,7 +148,7 @@
 
     private final char code;
 
-    private PatchType(final char c) {
+    PatchType(final char c) {
       code = c;
     }
 
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchLineComment.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchLineComment.java
index c04b729..16b2d61 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchLineComment.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchLineComment.java
@@ -60,14 +60,14 @@
   public static final char STATUS_DRAFT = 'd';
   public static final char STATUS_PUBLISHED = 'P';
 
-  public static enum Status {
+  public enum Status {
     DRAFT(STATUS_DRAFT),
 
     PUBLISHED(STATUS_PUBLISHED);
 
     private final char code;
 
-    private Status(final char c) {
+    Status(final char c) {
       code = c;
     }
 
@@ -122,6 +122,9 @@
   @Column(id = 9, notNull = false)
   protected CommentRange range;
 
+  @Column(id = 10, notNull = false)
+  protected String tag;
+
   /**
    * The RevId for the commit to which this comment is referring.
    *
@@ -144,6 +147,25 @@
     setWrittenOn(when);
   }
 
+  public PatchLineComment(PatchLineComment o) {
+    key = o.key;
+    lineNbr = o.lineNbr;
+    author = o.author;
+    writtenOn = o.writtenOn;
+    status = o.status;
+    side = o.side;
+    message = o.message;
+    parentUuid = o.parentUuid;
+    revId = o.revId;
+    if (o.range != null) {
+      range = new CommentRange(
+          o.range.getStartLine(),
+          o.range.getStartCharacter(),
+          o.range.getEndLine(),
+          o.range.getEndCharacter());
+    }
+  }
+
   public PatchLineComment.Key getKey() {
     return key;
   }
@@ -230,6 +252,14 @@
     return revId;
   }
 
+  public void setTag(String tag) {
+    this.tag = tag;
+  }
+
+  public String getTag() {
+    return tag;
+  }
+
   @Override
   public boolean equals(Object o) {
     if (o instanceof PatchLineComment) {
@@ -243,7 +273,8 @@
           && Objects.equals(message, c.getMessage())
           && Objects.equals(parentUuid, c.getParentUuid())
           && Objects.equals(range, c.getRange())
-          && Objects.equals(revId, c.getRevId());
+          && Objects.equals(revId, c.getRevId())
+          && Objects.equals(tag, c.getTag());
     }
     return false;
   }
@@ -270,6 +301,7 @@
     builder.append("range=").append(Objects.toString(range, ""))
       .append(',');
     builder.append("revId=").append(revId != null ? revId.get() : "");
+    builder.append("tag=").append(Objects.toString(tag, ""));
     builder.append('}');
     return builder.toString();
   }
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchSetApproval.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchSetApproval.java
index c89be30..1d0d29b 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchSetApproval.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchSetApproval.java
@@ -90,6 +90,9 @@
   @Column(id = 3)
   protected Timestamp granted;
 
+  @Column(id = 6, notNull = false)
+  protected String tag;
+
   // DELETED: id = 4 (changeOpen)
   // DELETED: id = 5 (changeSortKey)
 
@@ -145,6 +148,10 @@
     }
   }
 
+  public void setTag(String t) {
+    tag = t;
+  }
+
   public String getLabel() {
     return getLabelId().get();
   }
@@ -153,10 +160,14 @@
     return LabelId.LEGACY_SUBMIT_NAME.equals(getLabel());
   }
 
+  public String getTag() {
+    return tag;
+  }
+
   @Override
   public String toString() {
     return new StringBuilder().append('[').append(key).append(": ")
-        .append(value).append(']').toString();
+        .append(value).append(",tag:").append(tag).append(']').toString();
   }
 
   @Override
@@ -165,13 +176,14 @@
       PatchSetApproval p = (PatchSetApproval) o;
       return Objects.equals(key, p.key)
           && Objects.equals(value, p.value)
-          && Objects.equals(granted, p.granted);
+          && Objects.equals(granted, p.granted)
+          && Objects.equals(tag, p.tag);
     }
     return false;
   }
 
   @Override
   public int hashCode() {
-    return Objects.hash(key, value, granted);
+    return Objects.hash(key, value, granted, tag);
   }
 }
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Project.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Project.java
index af9e75c..86e6894 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Project.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Project.java
@@ -24,7 +24,7 @@
 public final class Project {
   /** Project name key */
   public static class NameKey extends
-      StringKey<com.google.gwtorm.client.Key<?>>{
+      StringKey<com.google.gwtorm.client.Key<?>> {
     private static final long serialVersionUID = 1L;
 
     @Column(id = 1)
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/RefNames.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/RefNames.java
index d2250cf..85ebdb1 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/RefNames.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/RefNames.java
@@ -95,37 +95,36 @@
 
   public static String refsDraftComments(Account.Id accountId,
       Change.Id changeId) {
-    StringBuilder r = buildRefsPrefix(REFS_DRAFT_COMMENTS, accountId);
+    StringBuilder r = buildRefsPrefix(REFS_DRAFT_COMMENTS, accountId.get());
     r.append(changeId.get());
     return r.toString();
   }
 
   public static String refsDraftCommentsPrefix(Account.Id accountId) {
-    return buildRefsPrefix(REFS_DRAFT_COMMENTS, accountId).toString();
+    return buildRefsPrefix(REFS_DRAFT_COMMENTS, accountId.get()).toString();
   }
 
-  public static String refsStarredChanges(Account.Id accountId,
-      Change.Id changeId) {
-    StringBuilder r = buildRefsPrefix(REFS_STARRED_CHANGES, accountId);
-    r.append(changeId.get());
+  public static String refsStarredChanges(Change.Id changeId,
+      Account.Id accountId) {
+    StringBuilder r = buildRefsPrefix(REFS_STARRED_CHANGES, changeId.get());
+    r.append(accountId.get());
     return r.toString();
   }
 
-  public static String refsStarredChangesPrefix(Account.Id accountId) {
-    return buildRefsPrefix(REFS_STARRED_CHANGES, accountId).toString();
+  public static String refsStarredChangesPrefix(Change.Id changeId) {
+    return buildRefsPrefix(REFS_STARRED_CHANGES, changeId.get()).toString();
   }
 
-  private static StringBuilder buildRefsPrefix(String prefix,
-      Account.Id accountId) {
+  private static StringBuilder buildRefsPrefix(String prefix, int id) {
     StringBuilder r = new StringBuilder();
     r.append(prefix);
-    int n = accountId.get() % 100;
+    int n = id % 100;
     if (n < 10) {
       r.append('0');
     }
     r.append(n);
     r.append('/');
-    r.append(accountId.get());
+    r.append(id);
     r.append('/');
     return r;
   }
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/StarredChange.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/StarredChange.java
deleted file mode 100644
index d427b09..0000000
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/StarredChange.java
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright (C) 2008 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.reviewdb.client;
-
-import com.google.gwtorm.client.Column;
-import com.google.gwtorm.client.CompoundKey;
-
-/** A {@link Change} starred by an {@link Account}. */
-public class StarredChange {
-  public static class Key extends CompoundKey<Account.Id> {
-    private static final long serialVersionUID = 1L;
-
-    @Column(id = 1)
-    protected Account.Id accountId;
-
-    @Column(id = 2)
-    protected Change.Id changeId;
-
-    protected Key() {
-      accountId = new Account.Id();
-      changeId = new Change.Id();
-    }
-
-    public Key(final Account.Id a, final Change.Id g) {
-      accountId = a;
-      changeId = g;
-    }
-
-    @Override
-    public Account.Id getParentKey() {
-      return accountId;
-    }
-
-    public Change.Id getChangeId() {
-      return changeId;
-    }
-
-    @Override
-    public com.google.gwtorm.client.Key<?>[] members() {
-      return new com.google.gwtorm.client.Key<?>[] {changeId};
-    }
-  }
-
-  @Column(id = 1, name = Column.NONE)
-  protected Key key;
-
-  protected StarredChange() {
-  }
-
-  public StarredChange(final StarredChange.Key k) {
-    key = k;
-  }
-
-  public StarredChange.Key getKey() {
-    return key;
-  }
-
-  public Account.Id getAccountId() {
-    return key.accountId;
-  }
-
-  public Change.Id getChangeId() {
-    return key.changeId;
-  }
-}
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ReviewDb.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ReviewDb.java
index 5d073e2..7b28f1f 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ReviewDb.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ReviewDb.java
@@ -68,10 +68,9 @@
   @Relation(id = 13)
   AccountGroupMemberAuditAccess accountGroupMembersAudit();
 
-  //Deleted @Relation(id = 17)
+  // Deleted @Relation(id = 17)
 
-  @Relation(id = 18)
-  StarredChangeAccess starredChanges();
+  // Deleted @Relation(id = 18)
 
   @Relation(id = 19)
   AccountProjectWatchAccess accountProjectWatches();
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ReviewDbUtil.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ReviewDbUtil.java
index 178b0fd..2460d57 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ReviewDbUtil.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ReviewDbUtil.java
@@ -38,7 +38,7 @@
       };
 
   private static final Ordering<? extends IntKey<?>> INT_KEY_ORDERING =
-      Ordering.natural().onResultOf(INT_KEY_FUNCTION);
+      Ordering.natural().nullsFirst().onResultOf(INT_KEY_FUNCTION).nullsFirst();
 
   @SuppressWarnings("unchecked")
   public static <K extends IntKey<?>> Ordering<K> intKeyOrdering() {
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ReviewDbWrapper.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ReviewDbWrapper.java
index deecba9..05793b5 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ReviewDbWrapper.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ReviewDbWrapper.java
@@ -114,11 +114,6 @@
   }
 
   @Override
-  public StarredChangeAccess starredChanges() {
-    return delegate.starredChanges();
-  }
-
-  @Override
   public AccountProjectWatchAccess accountProjectWatches() {
     return delegate.accountProjectWatches();
   }
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/StarredChangeAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/StarredChangeAccess.java
deleted file mode 100644
index 5f57fe7..0000000
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/StarredChangeAccess.java
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (C) 2008 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.reviewdb.server;
-
-import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.reviewdb.client.StarredChange;
-import com.google.gwtorm.server.Access;
-import com.google.gwtorm.server.OrmException;
-import com.google.gwtorm.server.PrimaryKey;
-import com.google.gwtorm.server.Query;
-import com.google.gwtorm.server.ResultSet;
-
-public interface StarredChangeAccess extends
-    Access<StarredChange, StarredChange.Key> {
-  @Override
-  @PrimaryKey("key")
-  StarredChange get(StarredChange.Key key) throws OrmException;
-
-  @Query("WHERE key.accountId = ?")
-  ResultSet<StarredChange> byAccount(Account.Id id) throws OrmException;
-
-  @Query("WHERE key.changeId = ?")
-  ResultSet<StarredChange> byChange(Change.Id id) throws OrmException;
-}
diff --git a/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_generic.sql b/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_generic.sql
index b8ebdde..9242fe0 100644
--- a/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_generic.sql
+++ b/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_generic.sql
@@ -86,10 +86,3 @@
 -- PatchSetAccess
 CREATE INDEX patch_sets_byRevision
 ON patch_sets (revision);
-
--- *********************************************************************
--- StarredChangeAccess
---    @PrimaryKey covers: byAccount
-
-CREATE INDEX starred_changes_byChange
-ON starred_changes (change_id);
diff --git a/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_maxdb.sql b/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_maxdb.sql
index d7135a2..6934eb2 100644
--- a/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_maxdb.sql
+++ b/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_maxdb.sql
@@ -95,11 +95,3 @@
 CREATE INDEX patch_sets_byRevision
 ON patch_sets (revision)
 #
-
--- *********************************************************************
--- StarredChangeAccess
---    @PrimaryKey covers: byAccount
-
-CREATE INDEX starred_changes_byChange
-ON starred_changes (change_id)
-#
diff --git a/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_postgres.sql b/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_postgres.sql
index b0b6b6f..f146785 100644
--- a/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_postgres.sql
+++ b/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_postgres.sql
@@ -135,11 +135,3 @@
 -- PatchSetAccess
 CREATE INDEX patch_sets_byRevision
 ON patch_sets (revision);
-
--- *********************************************************************
--- StarredChangeAccess
---    @PrimaryKey covers: byAccount
-
-CREATE INDEX starred_changes_byChange
-ON starred_changes (change_id);
-
diff --git a/gerrit-reviewdb/src/test/java/com/google/gerrit/reviewdb/client/RefNamesTest.java b/gerrit-reviewdb/src/test/java/com/google/gerrit/reviewdb/client/RefNamesTest.java
index 844f893..6797ffb 100644
--- a/gerrit-reviewdb/src/test/java/com/google/gerrit/reviewdb/client/RefNamesTest.java
+++ b/gerrit-reviewdb/src/test/java/com/google/gerrit/reviewdb/client/RefNamesTest.java
@@ -50,14 +50,14 @@
 
   @Test
   public void refsStarredChanges() throws Exception {
-    assertThat(RefNames.refsStarredChanges(accountId, changeId))
-      .isEqualTo("refs/starred-changes/23/1011123/67473");
+    assertThat(RefNames.refsStarredChanges(changeId, accountId))
+      .isEqualTo("refs/starred-changes/73/67473/1011123");
   }
 
   @Test
   public void refsStarredChangesPrefix() throws Exception {
-    assertThat(RefNames.refsStarredChangesPrefix(accountId))
-      .isEqualTo("refs/starred-changes/23/1011123/");
+    assertThat(RefNames.refsStarredChangesPrefix(changeId))
+      .isEqualTo("refs/starred-changes/73/67473/");
   }
 
   @Test
diff --git a/gerrit-server/src/main/java/com/google/gerrit/metrics/Description.java b/gerrit-server/src/main/java/com/google/gerrit/metrics/Description.java
index 43e5c8a..48358b7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/metrics/Description.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/metrics/Description.java
@@ -44,7 +44,7 @@
     }
   }
 
-  public static enum FieldOrdering {
+  public enum FieldOrdering {
     /** Default ordering places fields at end of the parent metric name. */
     AT_END,
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/rules/PrologEnvironment.java b/gerrit-server/src/main/java/com/google/gerrit/rules/PrologEnvironment.java
index 26c0fd0..de54a0b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/rules/PrologEnvironment.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/rules/PrologEnvironment.java
@@ -54,7 +54,7 @@
   private static final Logger log =
       LoggerFactory.getLogger(PrologEnvironment.class);
 
-  public static interface Factory {
+  public interface Factory {
     /**
      * Construct a new Prolog interpreter.
      *
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/ChangeMessagesUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/ChangeMessagesUtil.java
index 07d4326..91647ff 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/ChangeMessagesUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/ChangeMessagesUtil.java
@@ -72,11 +72,11 @@
   public void addChangeMessage(ReviewDb db, ChangeUpdate update,
       ChangeMessage changeMessage) throws OrmException {
     checkState(
-        Objects.equals(changeMessage.getAuthor(),
-            update.getUser().getAccountId()),
-        "cannot store change message of %s in update of %s",
-        changeMessage.getAuthor(), update.getUser().getAccountId());
+        Objects.equals(changeMessage.getAuthor(), update.getAccountId()),
+        "cannot store change message by %s in update by %s",
+        changeMessage.getAuthor(), update.getAccountId());
     update.setChangeMessage(changeMessage.getMessage());
+    update.setTag(changeMessage.getTag());
     db.changeMessages().insert(Collections.singleton(changeMessage));
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java b/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java
index 50b20f0..fb75091b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java
@@ -338,7 +338,7 @@
             FluentIterable.from(
               starredQuery != null
               ? starredQuery
-              : starredChangesUtil.query(accountId))
+              : starredChangesUtil.queryFromIndex(accountId))
             .toSet();
       } finally {
         starredQuery = null;
@@ -356,7 +356,7 @@
 
   public void asyncStarredChanges() {
     if (starredChanges == null && starredChangesUtil != null) {
-      starredQuery = starredChangesUtil.query(accountId);
+      starredQuery = starredChangesUtil.queryFromIndex(accountId);
     }
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/PatchLineCommentsUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/PatchLineCommentsUtil.java
index 3423e0b..fa31ed5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/PatchLineCommentsUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/PatchLineCommentsUtil.java
@@ -311,7 +311,7 @@
 
   public void deleteAllDraftsFromAllUsers(Change.Id changeId)
       throws IOException {
-    try (Repository repo = repoManager.openMetadataRepository(allUsers);
+    try (Repository repo = repoManager.openRepository(allUsers);
         RevWalk rw = new RevWalk(repo)) {
       BatchRefUpdate bru = repo.getRefDatabase().newBatchUpdate();
       for (Ref ref : getDraftRefs(repo, changeId).values()) {
@@ -373,7 +373,7 @@
   }
 
   private Set<String> getRefNamesAllUsers(String prefix) throws OrmException {
-    try (Repository repo = repoManager.openMetadataRepository(allUsers)) {
+    try (Repository repo = repoManager.openRepository(allUsers)) {
       RefDatabase refDb = repo.getRefDatabase();
       return refDb.getRefs(prefix).keySet();
     } catch (IOException e) {
@@ -383,7 +383,7 @@
 
   public Map<String, Ref> getDraftRefs(Change.Id changeId)
       throws OrmException {
-    try (Repository repo = repoManager.openMetadataRepository(allUsers)) {
+    try (Repository repo = repoManager.openRepository(allUsers)) {
       return getDraftRefs(repo, changeId);
     } catch (IOException e) {
       throw new OrmException(e);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/PatchSetUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/PatchSetUtil.java
index 1bbd735..0dcf3bf 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/PatchSetUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/PatchSetUtil.java
@@ -96,7 +96,7 @@
 
     PatchSet ps = new PatchSet(psId);
     ps.setRevision(new RevId(commit.name()));
-    ps.setUploader(update.getUser().getAccountId());
+    ps.setUploader(update.getAccountId());
     ps.setCreatedOn(new Timestamp(update.getWhen().getTime()));
     ps.setDraft(draft);
     ps.setGroups(groups);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/StarredChangesUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/StarredChangesUtil.java
index 60c41ef..72ee0ef 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/StarredChangesUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/StarredChangesUtil.java
@@ -14,19 +14,28 @@
 
 package com.google.gerrit.server;
 
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import com.google.common.base.CharMatcher;
 import com.google.common.base.Function;
-import com.google.common.base.Predicate;
+import com.google.common.base.Joiner;
+import com.google.common.base.Splitter;
 import com.google.common.collect.FluentIterable;
-import com.google.common.collect.Iterators;
-import com.google.common.collect.Lists;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSortedSet;
+import com.google.common.collect.Iterables;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.client.RefNames;
-import com.google.gerrit.reviewdb.client.StarredChange;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.config.AllUsersName;
 import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.notedb.NotesMigration;
+import com.google.gerrit.server.index.change.ChangeField;
+import com.google.gerrit.server.index.change.ChangeIndexer;
+import com.google.gerrit.server.project.NoSuchChangeException;
+import com.google.gerrit.server.query.change.ChangeData;
+import com.google.gerrit.server.query.change.InternalChangeQuery;
 import com.google.gwtorm.server.ListResultSet;
 import com.google.gwtorm.server.OrmException;
 import com.google.gwtorm.server.ResultSet;
@@ -39,6 +48,8 @@
 import org.eclipse.jgit.lib.NullProgressMonitor;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.ObjectLoader;
+import org.eclipse.jgit.lib.ObjectReader;
 import org.eclipse.jgit.lib.PersonIdent;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.RefDatabase;
@@ -51,68 +62,51 @@
 
 import java.io.IOException;
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
 
 @Singleton
 public class StarredChangesUtil {
   private static final Logger log =
       LoggerFactory.getLogger(StarredChangesUtil.class);
 
+  private static final String DEFAULT_LABEL = "star";
+  public static final ImmutableSortedSet<String> DEFAULT_LABELS =
+      ImmutableSortedSet.of(DEFAULT_LABEL);
+
   private final GitRepositoryManager repoManager;
   private final AllUsersName allUsers;
-  private final NotesMigration migration;
   private final Provider<ReviewDb> dbProvider;
   private final PersonIdent serverIdent;
+  private final ChangeIndexer indexer;
+  private final Provider<InternalChangeQuery> queryProvider;
 
   @Inject
   StarredChangesUtil(GitRepositoryManager repoManager,
       AllUsersName allUsers,
-      NotesMigration migration,
       Provider<ReviewDb> dbProvider,
-      @GerritPersonIdent PersonIdent serverIdent) {
+      @GerritPersonIdent PersonIdent serverIdent,
+      ChangeIndexer indexer,
+      Provider<InternalChangeQuery> queryProvider) {
     this.repoManager = repoManager;
     this.allUsers = allUsers;
-    this.migration = migration;
     this.dbProvider = dbProvider;
     this.serverIdent = serverIdent;
+    this.indexer = indexer;
+    this.queryProvider = queryProvider;
   }
 
-  public void star(Account.Id accountId, Change.Id changeId)
-      throws OrmException {
-    dbProvider.get().starredChanges()
-        .insert(Collections.singleton(new StarredChange(
-            new StarredChange.Key(accountId, changeId))));
-    if (!migration.writeAccounts()) {
-      return;
-    }
-    try (Repository repo = repoManager.openMetadataRepository(allUsers);
-        RevWalk rw = new RevWalk(repo)) {
-      RefUpdate u = repo.updateRef(
-          RefNames.refsStarredChanges(accountId, changeId));
-      u.setExpectedOldObjectId(ObjectId.zeroId());
-      u.setNewObjectId(emptyTree(repo));
-      u.setRefLogIdent(serverIdent);
-      u.setRefLogMessage("Star change " + changeId.get(), false);
-      RefUpdate.Result result = u.update(rw);
-      switch (result) {
-        case NEW:
-          return;
-        case FAST_FORWARD:
-        case FORCED:
-        case IO_FAILURE:
-        case LOCK_FAILURE:
-        case NOT_ATTEMPTED:
-        case NO_CHANGE:
-        case REJECTED:
-        case REJECTED_CURRENT_BRANCH:
-        case RENAMED:
-        default:
-          throw new OrmException(
-              String.format("Star change %d for account %d failed: %s",
-                  changeId.get(), accountId.get(), result.name()));
-      }
+  public void star(Account.Id accountId, Project.NameKey project,
+      Change.Id changeId) throws OrmException {
+    try (Repository repo = repoManager.openRepository(allUsers)) {
+      String refName = RefNames.refsStarredChanges(changeId, accountId);
+      ObjectId oldObjectId = getObjectId(repo, refName);
+      SortedSet<String> labels = readLabels(repo, oldObjectId);
+      labels.add(DEFAULT_LABEL);
+      updateLabels(repo, refName, oldObjectId, labels);
+      indexer.index(dbProvider.get(), project, changeId);
     } catch (IOException e) {
       throw new OrmException(
           String.format("Star change %d for account %d failed",
@@ -120,32 +114,19 @@
     }
   }
 
-  private static ObjectId emptyTree(Repository repo) throws IOException {
-    try (ObjectInserter oi = repo.newObjectInserter()) {
-      ObjectId id = oi.insert(Constants.OBJ_TREE, new byte[] {});
-      oi.flush();
-      return id;
-    }
-  }
-
-  public void unstar(Account.Id accountId, Change.Id changeId)
-      throws OrmException {
-    dbProvider.get().starredChanges()
-        .delete(Collections.singleton(new StarredChange(
-            new StarredChange.Key(accountId, changeId))));
-    if (!migration.writeAccounts()) {
-      return;
-    }
-    try (Repository repo = repoManager.openMetadataRepository(allUsers);
+  public void unstar(Account.Id accountId, Project.NameKey project,
+      Change.Id changeId) throws OrmException {
+    try (Repository repo = repoManager.openRepository(allUsers);
         RevWalk rw = new RevWalk(repo)) {
       RefUpdate u = repo.updateRef(
-          RefNames.refsStarredChanges(accountId, changeId));
+          RefNames.refsStarredChanges(changeId, accountId));
       u.setForceUpdate(true);
       u.setRefLogIdent(serverIdent);
       u.setRefLogMessage("Unstar change " + changeId.get(), true);
       RefUpdate.Result result = u.delete();
       switch (result) {
         case FORCED:
+          indexer.index(dbProvider.get(), project, changeId);
           return;
         case FAST_FORWARD:
         case IO_FAILURE:
@@ -168,20 +149,16 @@
     }
   }
 
-  public void unstarAll(Change.Id changeId) throws OrmException {
-    dbProvider.get().starredChanges().delete(
-        dbProvider.get().starredChanges().byChange(changeId));
-    if (!migration.writeAccounts()) {
-      return;
-    }
-    try (Repository repo = repoManager.openMetadataRepository(allUsers);
+  public void unstarAll(Project.NameKey project, Change.Id changeId)
+      throws OrmException, NoSuchChangeException {
+    try (Repository repo = repoManager.openRepository(allUsers);
         RevWalk rw = new RevWalk(repo)) {
       BatchRefUpdate batchUpdate = repo.getRefDatabase().newBatchUpdate();
       batchUpdate.setAllowNonFastForwards(true);
       batchUpdate.setRefLogIdent(serverIdent);
       batchUpdate.setRefLogMessage("Unstar change " + changeId.get(), true);
-      for (Account.Id accountId : byChange(changeId)) {
-        String refName = RefNames.refsStarredChanges(accountId, changeId);
+      for (Account.Id accountId : byChangeFromIndex(changeId)) {
+        String refName = RefNames.refsStarredChanges(changeId, accountId);
         Ref ref = repo.getRefDatabase().getRef(refName);
         batchUpdate.addCommand(new ReceiveCommand(ref.getObjectId(),
             ObjectId.zeroId(), refName));
@@ -194,52 +171,51 @@
               changeId.get(), command.getRefName(), command.getResult()));
         }
       }
+      indexer.index(dbProvider.get(), project, changeId);
     } catch (IOException e) {
       throw new OrmException(
           String.format("Unstar change %d failed", changeId.get()), e);
     }
   }
 
-  public Iterable<Account.Id> byChange(final Change.Id changeId)
+  public Set<Account.Id> byChange(Change.Id changeId)
       throws OrmException {
-    if (!migration.readAccounts()) {
-      return FluentIterable
-          .from(dbProvider.get().starredChanges().byChange(changeId))
-          .transform(new Function<StarredChange, Account.Id>() {
-            @Override
-            public Account.Id apply(StarredChange in) {
-              return in.getAccountId();
-            }
-          });
-    }
-    return FluentIterable.from(getRefNames(RefNames.REFS_STARRED_CHANGES))
-        .filter(new Predicate<String>() {
-          @Override
-          public boolean apply(String refPart) {
-            return refPart.endsWith("/" + changeId.get());
-          }
-        })
+    return FluentIterable
+        .from(getRefNames(RefNames.refsStarredChangesPrefix(changeId)))
         .transform(new Function<String, Account.Id>() {
           @Override
           public Account.Id apply(String refPart) {
-            return Account.Id.fromRefPart(refPart);
+            return Account.Id.parse(refPart);
           }
-        });
+        }).toSet();
   }
 
-  public ResultSet<Change.Id> query(Account.Id accountId) {
-    try {
-      if (!migration.readAccounts()) {
-        return new ChangeIdResultSet(
-            dbProvider.get().starredChanges().byAccount(accountId));
-      }
+  public Set<Account.Id> byChangeFromIndex(Change.Id changeId)
+      throws OrmException, NoSuchChangeException {
+    Set<String> fields = ImmutableSet.of(
+        ChangeField.ID.getName(),
+        ChangeField.STARREDBY.getName());
+    List<ChangeData> changeData = queryProvider.get().setRequestedFields(fields)
+        .byLegacyChangeId(changeId);
+    if (changeData.size() != 1) {
+      throw new NoSuchChangeException(changeId);
+    }
+    return changeData.get(0).starredBy();
+  }
 
+  @Deprecated
+  public ResultSet<Change.Id> queryFromIndex(final Account.Id accountId) {
+    try {
+      Set<String> fields = ImmutableSet.of(
+          ChangeField.ID.getName());
+      List<ChangeData> changeData =
+          queryProvider.get().setRequestedFields(fields).byIsStarred(accountId);
       return new ListResultSet<>(FluentIterable
-          .from(getRefNames(RefNames.refsStarredChangesPrefix(accountId)))
-          .transform(new Function<String, Change.Id>() {
+          .from(changeData)
+          .transform(new Function<ChangeData, Change.Id>() {
             @Override
-            public Change.Id apply(String changeId) {
-              return Change.Id.parse(changeId);
+            public Change.Id apply(ChangeData cd) {
+              return cd.getId();
             }
           }).toList());
     } catch (OrmException | RuntimeException e) {
@@ -251,7 +227,7 @@
   }
 
   private Set<String> getRefNames(String prefix) throws OrmException {
-    try (Repository repo = repoManager.openMetadataRepository(allUsers)) {
+    try (Repository repo = repoManager.openRepository(allUsers)) {
       RefDatabase refDb = repo.getRefDatabase();
       return refDb.getRefs(prefix).keySet();
     } catch (IOException e) {
@@ -259,37 +235,86 @@
     }
   }
 
-  private static class ChangeIdResultSet implements ResultSet<Change.Id> {
-    private static final Function<StarredChange, Change.Id>
-        STARRED_CHANGE_TO_CHANGE_ID =
-            new Function<StarredChange, Change.Id>() {
-              @Override
-              public Change.Id apply(StarredChange starredChange) {
-                return starredChange.getChangeId();
-              }
-            };
+  private static ObjectId getObjectId(Repository repo, String refName)
+      throws IOException {
+    Ref ref = repo.exactRef(refName);
+    return ref != null ? ref.getObjectId() : ObjectId.zeroId();
+  }
 
-    private final ResultSet<StarredChange> starredChangesResultSet;
-
-    ChangeIdResultSet(ResultSet<StarredChange> starredChangesResultSet) {
-      this.starredChangesResultSet = starredChangesResultSet;
+  private static TreeSet<String> readLabels(Repository repo, ObjectId id)
+      throws IOException {
+    if (ObjectId.zeroId().equals(id)) {
+      return new TreeSet<>();
     }
 
-    @Override
-    public Iterator<Change.Id> iterator() {
-      return Iterators.transform(starredChangesResultSet.iterator(),
-          STARRED_CHANGE_TO_CHANGE_ID);
+    try (ObjectReader reader = repo.newObjectReader()) {
+      ObjectLoader obj = reader.open(id, Constants.OBJ_BLOB);
+      TreeSet<String> labels = new TreeSet<>();
+      Iterables.addAll(labels,
+          Splitter.on(CharMatcher.whitespace()).omitEmptyStrings()
+              .split(new String(obj.getCachedBytes(Integer.MAX_VALUE), UTF_8)));
+      return labels;
+    }
+  }
+
+  public static ObjectId writeLabels(Repository repo, SortedSet<String> labels)
+      throws IOException {
+    SortedSet<String> invalidLabels = validateLabels(labels);
+    if (!invalidLabels.isEmpty()) {
+      throw new IllegalArgumentException(
+          String.format("Invalid star labels: %s",
+              Joiner.on(", ").join(labels)));
     }
 
-    @Override
-    public List<Change.Id> toList() {
-      return Lists.transform(starredChangesResultSet.toList(),
-          STARRED_CHANGE_TO_CHANGE_ID);
+    try (ObjectInserter oi = repo.newObjectInserter()) {
+      ObjectId id = oi.insert(Constants.OBJ_BLOB,
+          Joiner.on("\n").join(labels).getBytes(UTF_8));
+      oi.flush();
+      return id;
+    }
+  }
+
+  private static SortedSet<String> validateLabels(Set<String> labels) {
+    if (labels == null) {
+      return ImmutableSortedSet.of();
     }
 
-    @Override
-    public void close() {
-      starredChangesResultSet.close();
+    SortedSet<String> invalidLabels = new TreeSet<>();
+    for (String label : labels) {
+      if (CharMatcher.whitespace().matchesAnyOf(label)) {
+        invalidLabels.add(label);
+      }
+    }
+    return invalidLabels;
+  }
+
+  private void updateLabels(Repository repo, String refName,
+      ObjectId oldObjectId, SortedSet<String> labels)
+          throws IOException, OrmException {
+    try (RevWalk rw = new RevWalk(repo)) {
+      RefUpdate u = repo.updateRef(refName);
+      u.setExpectedOldObjectId(oldObjectId);
+      u.setForceUpdate(true);
+      u.setNewObjectId(writeLabels(repo, labels));
+      u.setRefLogIdent(serverIdent);
+      u.setRefLogMessage("Update star labels", true);
+      RefUpdate.Result result = u.update(rw);
+      switch (result) {
+        case NEW:
+        case FORCED:
+        case NO_CHANGE:
+        case FAST_FORWARD:
+          return;
+        case IO_FAILURE:
+        case LOCK_FAILURE:
+        case NOT_ATTEMPTED:
+        case REJECTED:
+        case REJECTED_CURRENT_BRANCH:
+        case RENAMED:
+          throw new OrmException(
+              String.format("Update star labels on ref %s failed: %s", refName,
+                  result.name()));
+      }
     }
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/StringUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/StringUtil.java
index 2133dfb..0aef9e9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/StringUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/StringUtil.java
@@ -26,7 +26,7 @@
     { "\\x00", "\\x01", "\\x02", "\\x03", "\\x04", "\\x05", "\\x06", "\\a",
       "\\b",   "\\t",   "\\n",   "\\v",   "\\f",   "\\r",   "\\x0e", "\\x0f",
       "\\x10", "\\x11", "\\x12", "\\x13", "\\x14", "\\x15", "\\x16", "\\x17",
-      "\\x18", "\\x19", "\\x1a", "\\x1b", "\\x1c", "\\x1d", "\\x1e", "\\x1f" };
+      "\\x18", "\\x19", "\\x1a", "\\x1b", "\\x1c", "\\x1d", "\\x1e", "\\x1f", };
 
   /**
    * Escapes the input string so that all non-printable characters
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/WebLinks.java b/gerrit-server/src/main/java/com/google/gerrit/server/WebLinks.java
index 351de5e..6057f81 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/WebLinks.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/WebLinks.java
@@ -44,7 +44,7 @@
 
         @Override
         public boolean apply(WebLinkInfo link) {
-          if (link == null){
+          if (link == null) {
             return false;
           } else if (Strings.isNullOrEmpty(link.name)
               || Strings.isNullOrEmpty(link.url)) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java
index 9ac20f6..e801eb5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java
@@ -354,7 +354,7 @@
         }
         try {
           update(db, who, extId);
-        } catch(NameAlreadyUsedException | InvalidUserNameException e) {
+        } catch (NameAlreadyUsedException | InvalidUserNameException e) {
           throw new AccountException("Account update failed", e);
         }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountsCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountsCollection.java
index 80ea907..d54a999 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountsCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountsCollection.java
@@ -35,7 +35,7 @@
 @Singleton
 public class AccountsCollection implements
     RestCollection<TopLevelResource, AccountResource>,
-    AcceptsCreate<TopLevelResource>{
+    AcceptsCreate<TopLevelResource> {
   private final Provider<CurrentUser> self;
   private final AccountResolver resolver;
   private final AccountControl.Factory accountControlFactory;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityControl.java
index 9d580f5..0f78581 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityControl.java
@@ -39,7 +39,7 @@
 
 /** Access control management for server-wide capabilities. */
 public class CapabilityControl {
-  public static interface Factory {
+  public interface Factory {
     CapabilityControl create(CurrentUser user);
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityUtils.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityUtils.java
index c26b1ab..2bf147d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityUtils.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityUtils.java
@@ -32,6 +32,11 @@
       .getLogger(CapabilityUtils.class);
 
   public static void checkRequiresCapability(Provider<CurrentUser> userProvider,
+      String pluginName, Class<?> clazz) throws AuthException {
+    checkRequiresCapability(userProvider.get(), pluginName, clazz);
+  }
+
+  public static void checkRequiresCapability(CurrentUser user,
       String pluginName, Class<?> clazz)
       throws AuthException {
     RequiresCapability rc = getClassAnnotation(clazz, RequiresCapability.class);
@@ -45,7 +50,6 @@
           RequiresAnyCapability.class.getSimpleName()));
       throw new AuthException("cannot check capability");
     }
-    CurrentUser user = userProvider.get();
     CapabilityControl ctl = user.getCapabilities();
     if (ctl.canAdministrateServer()) {
       return;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/CreateAccount.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/CreateAccount.java
index f16c3ea..190db5f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/CreateAccount.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/CreateAccount.java
@@ -66,7 +66,7 @@
     public List<String> groups;
   }
 
-  public static interface Factory {
+  public interface Factory {
     CreateAccount create(String username);
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/CreateEmail.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/CreateEmail.java
index a78c23c..45dd971 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/CreateEmail.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/CreateEmail.java
@@ -42,7 +42,7 @@
 public class CreateEmail implements RestModifyView<AccountResource, EmailInput> {
   private static final Logger log = LoggerFactory.getLogger(CreateEmail.class);
 
-  public static interface Factory {
+  public interface Factory {
     CreateEmail create(String email);
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/EmailExpander.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/EmailExpander.java
index 166f97e..75408c8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/EmailExpander.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/EmailExpander.java
@@ -23,7 +23,7 @@
 
   String expand(String user);
 
-  public static class None implements EmailExpander {
+  class None implements EmailExpander {
     public static final None INSTANCE = new None();
 
     public static boolean canHandle(final String fmt) {
@@ -44,7 +44,7 @@
     }
   }
 
-  public static class Simple implements EmailExpander {
+  class Simple implements EmailExpander {
     private static final String PLACEHOLDER = "{0}";
 
     public static boolean canHandle(final String fmt) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupCacheImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupCacheImpl.java
index bf04234..e5e2f99 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupCacheImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupCacheImpl.java
@@ -95,7 +95,7 @@
       Optional<AccountGroup> g = byId.get(groupId);
       return g.isPresent() ? g.get() : missing(groupId);
     } catch (ExecutionException e) {
-      log.warn("Cannot load group "+groupId, e);
+      log.warn("Cannot load group " + groupId, e);
       return missing(groupId);
     }
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupMembership.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupMembership.java
index d7a97fb..8612d74 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupMembership.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupMembership.java
@@ -24,7 +24,7 @@
  * the presence of a user in a particular group.
  */
 public interface GroupMembership {
-  public static final GroupMembership EMPTY =
+  GroupMembership EMPTY =
       new ListGroupMembership(Collections.<AccountGroup.UUID>emptySet());
 
   /**
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/StarredChanges.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/StarredChanges.java
index e69bc0f..1ed29a7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/StarredChanges.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/StarredChanges.java
@@ -42,6 +42,8 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.IOException;
+
 @Singleton
 public class StarredChanges implements
     ChildCollection<AccountResource, AccountResource.StarredChange>,
@@ -99,7 +101,7 @@
   @SuppressWarnings("unchecked")
   @Override
   public RestModifyView<AccountResource, EmptyInput> create(
-      AccountResource parent, IdString id) throws UnprocessableEntityException{
+      AccountResource parent, IdString id) throws UnprocessableEntityException {
     try {
       return createProvider.get()
           .setChange(changes.parse(TopLevelResource.INSTANCE, id));
@@ -130,12 +132,13 @@
 
     @Override
     public Response<?> apply(AccountResource rsrc, EmptyInput in)
-        throws AuthException, OrmException {
+        throws AuthException, OrmException, IOException {
       if (self.get() != rsrc.getUser()) {
         throw new AuthException("not allowed to add starred change");
       }
       try {
-        starredChangesUtil.star(self.get().getAccountId(), change.getId());
+        starredChangesUtil.star(self.get().getAccountId(), change.getProject(),
+            change.getId());
       } catch (OrmDuplicateKeyException e) {
         return Response.none();
       }
@@ -177,12 +180,12 @@
 
     @Override
     public Response<?> apply(AccountResource.StarredChange rsrc,
-        EmptyInput in) throws AuthException, OrmException {
+        EmptyInput in) throws AuthException, OrmException, IOException {
       if (self.get() != rsrc.getUser()) {
         throw new AuthException("not allowed remove starred change");
       }
       starredChangesUtil.unstar(self.get().getAccountId(),
-          rsrc.getChange().getId());
+          rsrc.getChange().getProject(), rsrc.getChange().getId());
       return Response.none();
     }
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java
index 33f1dbb..b3126d3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.server.api.accounts;
 
+import com.google.gerrit.common.RawInputUtil;
 import com.google.gerrit.common.errors.EmailException;
 import com.google.gerrit.extensions.api.accounts.AccountApi;
 import com.google.gerrit.extensions.api.accounts.EmailInput;
@@ -23,17 +24,20 @@
 import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
 import com.google.gerrit.extensions.common.AccountInfo;
 import com.google.gerrit.extensions.common.GpgKeyInfo;
+import com.google.gerrit.extensions.common.SshKeyInfo;
 import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.extensions.restapi.TopLevelResource;
 import com.google.gerrit.server.GpgException;
 import com.google.gerrit.server.account.AccountLoader;
 import com.google.gerrit.server.account.AccountResource;
+import com.google.gerrit.server.account.AddSshKey;
 import com.google.gerrit.server.account.CreateEmail;
 import com.google.gerrit.server.account.GetAvatar;
 import com.google.gerrit.server.account.GetDiffPreferences;
 import com.google.gerrit.server.account.GetEditPreferences;
 import com.google.gerrit.server.account.GetPreferences;
+import com.google.gerrit.server.account.GetSshKeys;
 import com.google.gerrit.server.account.SetDiffPreferences;
 import com.google.gerrit.server.account.SetEditPreferences;
 import com.google.gerrit.server.account.SetPreferences;
@@ -70,6 +74,8 @@
   private final StarredChanges.Delete starredChangesDelete;
   private final CreateEmail.Factory createEmailFactory;
   private final GpgApiAdapter gpgApiAdapter;
+  private final GetSshKeys getSshKeys;
+  private final AddSshKey addSshKey;
 
   @Inject
   AccountApiImpl(AccountLoader.Factory ailf,
@@ -85,6 +91,8 @@
       StarredChanges.Delete starredChangesDelete,
       CreateEmail.Factory createEmailFactory,
       GpgApiAdapter gpgApiAdapter,
+      GetSshKeys getSshKeys,
+      AddSshKey addSshKey,
       @Assisted AccountResource account) {
     this.account = account;
     this.accountLoaderFactory = ailf;
@@ -99,6 +107,8 @@
     this.starredChangesCreate = starredChangesCreate;
     this.starredChangesDelete = starredChangesDelete;
     this.createEmailFactory = createEmailFactory;
+    this.getSshKeys = getSshKeys;
+    this.addSshKey = addSshKey;
     this.gpgApiAdapter = gpgApiAdapter;
   }
 
@@ -183,7 +193,7 @@
         IdString.fromUrl(id));
       starredChangesCreate.setChange(rsrc);
       starredChangesCreate.apply(account, new StarredChanges.EmptyInput());
-    } catch (OrmException e) {
+    } catch (OrmException | IOException e) {
       throw new RestApiException("Cannot star change", e);
     }
   }
@@ -197,7 +207,7 @@
           new AccountResource.StarredChange(account.getUser(), rsrc);
       starredChangesDelete.apply(starredChange,
           new StarredChanges.EmptyInput());
-    } catch (OrmException e) {
+    } catch (OrmException | IOException e) {
       throw new RestApiException("Cannot unstar change", e);
     }
   }
@@ -214,6 +224,26 @@
   }
 
   @Override
+  public List<SshKeyInfo> listSshKeys() throws RestApiException {
+    try {
+      return getSshKeys.apply(account);
+    } catch (OrmException e) {
+      throw new RestApiException("Cannot list SSH keys", e);
+    }
+  }
+
+  @Override
+  public SshKeyInfo addSshKey(String key) throws RestApiException {
+    AddSshKey.Input in = new AddSshKey.Input();
+    in.raw = RawInputUtil.create(key);
+    try {
+      return addSshKey.apply(account, in).value();
+    } catch (OrmException | IOException e) {
+      throw new RestApiException("Cannot add SSH key", e);
+    }
+  }
+
+  @Override
   public Map<String, GpgKeyInfo> listGpgKeys() throws RestApiException {
     try {
       return gpgApiAdapter.listGpgKeys(account);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountExternalIdCreator.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountExternalIdCreator.java
index 9c500b2..a0b9b4e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountExternalIdCreator.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountExternalIdCreator.java
@@ -32,6 +32,6 @@
    *
    * @return a list of external identifiers, or an empty list.
    */
-  public List<AccountExternalId> create(Account.Id id, String username,
+  List<AccountExternalId> create(Account.Id id, String username,
       String email);
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/cache/PersistentCache.java b/gerrit-server/src/main/java/com/google/gerrit/server/cache/PersistentCache.java
index 62623ea..60c806b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/cache/PersistentCache.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/cache/PersistentCache.java
@@ -18,7 +18,7 @@
 
   DiskStats diskStats();
 
-  public static class DiskStats {
+  class DiskStats {
     private final long size;
     private final long space;
     private final long hitCount;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ArchiveFormat.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ArchiveFormat.java
index 14fa7d6..335f201 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ArchiveFormat.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ArchiveFormat.java
@@ -31,7 +31,7 @@
   private final ArchiveCommand.Format<?> format;
   private final String mimeType;
 
-  private ArchiveFormat(String mimeType, ArchiveCommand.Format<?> format) {
+  ArchiveFormat(String mimeType, ArchiveCommand.Format<?> format) {
     this.format = format;
     this.mimeType = mimeType;
     ArchiveCommand.registerFormat(name(), format);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeEdits.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeEdits.java
index f6045c1..c821cf6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeEdits.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeEdits.java
@@ -403,7 +403,7 @@
             rsrc.getChangeEdit(),
             rsrc.getPath(),
             input.content);
-      } catch(InvalidChangeOperationException | IOException e) {
+      } catch (InvalidChangeOperationException | IOException e) {
         throw new ResourceConflictException(e.getMessage());
       }
       return Response.none();
@@ -434,7 +434,7 @@
         throws AuthException, ResourceConflictException {
       try {
         editModifier.deleteFile(rsrc.getChangeEdit(), rsrc.getPath());
-      } catch(InvalidChangeOperationException | IOException e) {
+      } catch (InvalidChangeOperationException | IOException e) {
         throw new ResourceConflictException(e.getMessage());
       }
       return Response.none();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeInserter.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeInserter.java
index 59c25e4..6af3e79 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeInserter.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeInserter.java
@@ -77,7 +77,7 @@
 import java.util.concurrent.ExecutorService;
 
 public class ChangeInserter extends BatchUpdate.InsertChangeOp {
-  public static interface Factory {
+  public interface Factory {
     ChangeInserter create(Change.Id cid, RevCommit rc, String refName);
   }
 
@@ -406,7 +406,7 @@
         List<LabelType> labels = changeControl.getLabelTypes().getLabelTypes();
         Map<String, Short> allApprovals = new HashMap<>();
         Map<String, Short> oldApprovals = new HashMap<>();
-        for (LabelType lt : labels){
+        for (LabelType lt : labels) {
           allApprovals.put(lt.getName(), (short) 0);
           oldApprovals.put(lt.getName(), null);
         }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
index 0f68ee2..a0d3fac 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
@@ -633,6 +633,7 @@
           continue;
         }
         Integer value;
+        String tag = null;
         Timestamp date = null;
         PatchSetApproval psa = current.get(accountId, lt.getName());
         if (psa != null) {
@@ -643,6 +644,7 @@
             // label.
             value = labelNormalizer.canVote(ctl, lt, accountId) ? 0 : null;
           }
+          tag = psa.getTag();
           date = psa.getGranted();
         } else {
           // Either the user cannot vote on this label, or they were added as a
@@ -650,7 +652,8 @@
           // user can vote on this label.
           value = labelNormalizer.canVote(ctl, lt, accountId) ? 0 : null;
         }
-        addApproval(e.getValue().label(), approvalInfo(accountId, value, date));
+        addApproval(e.getValue().label(),
+            approvalInfo(accountId, value, tag, date));
       }
     }
   }
@@ -708,7 +711,7 @@
 
       if (detailed) {
         for (Map.Entry<String, LabelWithStatus> entry : labels.entrySet()) {
-          ApprovalInfo ai = approvalInfo(accountId, 0, null);
+          ApprovalInfo ai = approvalInfo(accountId, 0, null, null);
           byLabel.put(entry.getKey(), ai);
           addApproval(entry.getValue().label(), ai);
         }
@@ -724,6 +727,7 @@
         if (info != null) {
           info.value = Integer.valueOf(val);
           info.date = psa.getGranted();
+          info.tag = psa.getTag();
         }
         if (!standard) {
           continue;
@@ -735,10 +739,12 @@
     return labels;
   }
 
-  private ApprovalInfo approvalInfo(Account.Id id, Integer value, Timestamp date) {
+  private ApprovalInfo approvalInfo(Account.Id id, Integer value, String tag,
+      Timestamp date) {
     ApprovalInfo ai = new ApprovalInfo(id.get());
     ai.value = value;
     ai.date = date;
+    ai.tag = tag;
     accountLoader.put(ai);
     return ai;
   }
@@ -816,6 +822,7 @@
         cmi.author = accountLoader.get(message.getAuthor());
         cmi.date = message.getWrittenOn();
         cmi.message = message.getMessage();
+        cmi.tag = message.getTag();
         cmi._revisionNumber = patchNum != null ? patchNum.get() : null;
         result.add(cmi);
       }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeKindCacheImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeKindCacheImpl.java
index b22c49f..10e6716 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeKindCacheImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeKindCacheImpl.java
@@ -288,8 +288,8 @@
   public static class ChangeKindWeigher implements Weigher<Key, ChangeKind> {
     @Override
     public int weigh(Key key, ChangeKind changeKind) {
-      return 16 + 2*36 + 2*key.strategyName.length() // Size of Key, 64 bit JVM
-          + 2*changeKind.name().length(); // Size of ChangeKind, 64 bit JVM
+      return 16 + 2 * 36 + 2 * key.strategyName.length() // Size of Key, 64 bit JVM
+          + 2 * changeKind.name().length(); // Size of ChangeKind, 64 bit JVM
     }
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/CommentJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/CommentJson.java
index b155b84..0af5656 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/CommentJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/CommentJson.java
@@ -136,6 +136,7 @@
     r.message = Strings.emptyToNull(c.getMessage());
     r.updated = c.getWrittenOn();
     r.range = toRange(c.getRange());
+    r.tag = c.getTag();
     if (loader != null) {
       r.author = loader.get(c.getAuthor());
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftChangeOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftChangeOp.java
index d90fc73..6ac17b2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftChangeOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftChangeOp.java
@@ -31,6 +31,7 @@
 import com.google.gerrit.server.git.BatchUpdate.ChangeContext;
 import com.google.gerrit.server.git.BatchUpdate.RepoContext;
 import com.google.gerrit.server.git.BatchUpdateReviewDb;
+import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.schema.DisabledChangesReviewDbWrapper;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
@@ -78,8 +79,8 @@
   }
 
   @Override
-  public boolean updateChange(ChangeContext ctx)
-      throws RestApiException, OrmException {
+  public boolean updateChange(ChangeContext ctx) throws RestApiException,
+      OrmException, IOException, NoSuchChangeException {
     checkState(ctx.getOrder() == BatchUpdate.Order.DB_BEFORE_REPO,
         "must use DeleteDraftChangeOp with DB_BEFORE_REPO");
     checkState(id == null, "cannot reuse DeleteDraftChangeOp");
@@ -117,7 +118,7 @@
 
     // Non-atomic operation on Accounts table; not much we can do to make it
     // atomic.
-    starredChangesUtil.unstarAll(id);
+    starredChangesUtil.unstarAll(change.getProject(), id);
 
     ctx.deleteChange();
     return true;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftPatchSet.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftPatchSet.java
index 59d4290..2edff4b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftPatchSet.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftPatchSet.java
@@ -35,6 +35,7 @@
 import com.google.gerrit.server.git.UpdateException;
 import com.google.gerrit.server.patch.PatchSetInfoFactory;
 import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
+import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -99,8 +100,8 @@
     }
 
     @Override
-    public boolean updateChange(ChangeContext ctx)
-        throws RestApiException, OrmException, IOException {
+    public boolean updateChange(ChangeContext ctx) throws RestApiException,
+        OrmException, IOException, NoSuchChangeException {
       patchSet = psUtil.get(ctx.getDb(), ctx.getNotes(), psId);
       if (patchSet == null) {
         return false; // Nothing to do.
@@ -148,7 +149,8 @@
     }
 
     private void deleteOrUpdateDraftChange(ChangeContext ctx)
-        throws OrmException, RestApiException {
+        throws OrmException, RestApiException, IOException,
+        NoSuchChangeException {
       Change c = ctx.getChange();
       if (deletedOnlyPatchSet()) {
         deleteChangeOp = deleteChangeOpProvider.get();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDiff.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDiff.java
index 92af1fa..3d02b83 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDiff.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDiff.java
@@ -164,8 +164,8 @@
           case INSERT:
           case REPLACE:
             List<Edit> internalEdit = edit instanceof ReplaceEdit
-              ? ((ReplaceEdit) edit).getInternalEdits()
-              : null;
+                ? ((ReplaceEdit) edit).getInternalEdits()
+                : null;
             content.addDiff(edit.getEndA(), edit.getEndB(), internalEdit);
             break;
           case EMPTY:
@@ -403,7 +403,7 @@
 
     private final DiffPreferencesInfo.Whitespace whitespace;
 
-    private IgnoreWhitespace(DiffPreferencesInfo.Whitespace whitespace) {
+    IgnoreWhitespace(DiffPreferencesInfo.Whitespace whitespace) {
       this.whitespace = whitespace;
     }
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRelated.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRelated.java
index b10d9f7..12e4276 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRelated.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRelated.java
@@ -81,7 +81,8 @@
         .byProjectGroups(rsrc.getChange().getProject(), groups);
     if (cds.isEmpty()) {
       return Collections.emptyList();
-    } if (cds.size() == 1
+    }
+    if (cds.size() == 1
         && cds.get(0).getId().equals(rsrc.getChange().getId())) {
       return Collections.emptyList();
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/MergeabilityCache.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/MergeabilityCache.java
index e83b539..93c4ac3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/MergeabilityCache.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/MergeabilityCache.java
@@ -23,7 +23,7 @@
 
 /** Cache for mergeability of commits into destination branches. */
 public interface MergeabilityCache {
-  public static class NotImplemented implements MergeabilityCache {
+  class NotImplemented implements MergeabilityCache {
     @Override
     public boolean get(ObjectId commit, Ref intoRef, SubmitType submitType,
         String mergeStrategy, Branch.NameKey dest, Repository repo) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Move.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Move.java
index f9dc069..6da57c9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Move.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Move.java
@@ -26,8 +26,8 @@
 import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.reviewdb.client.Branch;
 import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.reviewdb.client.ChangeMessage;
 import com.google.gerrit.reviewdb.client.Change.Status;
+import com.google.gerrit.reviewdb.client.ChangeMessage;
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.client.RefNames;
@@ -37,10 +37,10 @@
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.PatchSetUtil;
 import com.google.gerrit.server.git.BatchUpdate;
+import com.google.gerrit.server.git.BatchUpdate.ChangeContext;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.UpdateException;
 import com.google.gerrit.server.notedb.ChangeUpdate;
-import com.google.gerrit.server.git.BatchUpdate.ChangeContext;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.query.change.InternalChangeQuery;
 import com.google.gwtorm.server.OrmException;
@@ -108,7 +108,7 @@
     private Change change;
     private Branch.NameKey newDestKey;
 
-    public Op(ChangeControl ctl, MoveInput input) {
+    Op(ChangeControl ctl, MoveInput input) {
       this.input = input;
       this.caller = ctl.getUser().asIdentifiedUser();
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java
index 1853438..a70716a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java
@@ -68,7 +68,7 @@
   private static final Logger log =
       LoggerFactory.getLogger(PatchSetInserter.class);
 
-  public static interface Factory {
+  public interface Factory {
     PatchSetInserter create(RefControl refControl, PatchSet.Id psId,
         RevCommit commit);
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java
index bae54f2..e869c1b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java
@@ -444,6 +444,7 @@
           e.setSide(c.side == Side.PARENT ? (short) 0 : (short) 1);
           setCommentRevId(e, patchListCache, ctx.getChange(), ps);
           e.setMessage(c.message);
+          e.setTag(in.tag);
           if (c.range != null) {
             e.setRange(new CommentRange(
                 c.range.startLine,
@@ -500,6 +501,7 @@
       Map<String, PatchLineComment> drafts = Maps.newHashMap();
       for (PatchLineComment c : plcUtil.draftByChangeAuthor(
           ctx.getDb(), ctx.getNotes(), user.getAccountId())) {
+        c.setTag(in.tag);
         drafts.put(c.getKey().get(), c);
       }
       return drafts;
@@ -528,6 +530,7 @@
         PatchLineComment c, PatchSet ps) throws OrmException {
       c.setStatus(PatchLineComment.Status.PUBLISHED);
       c.setWrittenOn(ctx.getWhen());
+      c.setTag(in.tag);
       setCommentRevId(c, patchListCache, ctx.getChange(), checkNotNull(ps));
       return c;
     }
@@ -550,6 +553,37 @@
       }
     }
 
+    private Map<String, Short> getAllApprovals(LabelTypes labelTypes,
+        Map<String, Short> current, Map<String, Short> input) {
+      Map<String, Short> allApprovals = new HashMap<>();
+      for (LabelType lt : labelTypes.getLabelTypes()) {
+        allApprovals.put(lt.getName(), (short) 0);
+      }
+      // set approvals to existing votes
+      if (current != null) {
+        allApprovals.putAll(current);
+      }
+      // set approvals to new votes
+      if (input != null) {
+        allApprovals.putAll(input);
+      }
+      return allApprovals;
+    }
+
+    private Map<String, Short> getPreviousApprovals(
+        Map<String, Short> allApprovals, Map<String, Short> current) {
+      Map<String, Short> previous = new HashMap<>();
+      for (Map.Entry<String, Short> approval : allApprovals.entrySet()) {
+        // assume vote is 0 if there is no vote
+        if (!current.containsKey(approval.getKey())) {
+          previous.put(approval.getKey(), (short) 0);
+        } else {
+          previous.put(approval.getKey(), current.get(approval.getKey()));
+        }
+      }
+      return previous;
+    }
+
     private boolean updateLabels(ChangeContext ctx)
         throws OrmException, ResourceConflictException {
       Map<String, Short> inLabels = MoreObjects.firstNonNull(in.labels,
@@ -565,27 +599,13 @@
       List<PatchSetApproval> del = Lists.newArrayList();
       List<PatchSetApproval> ups = Lists.newArrayList();
       Map<String, PatchSetApproval> current = scanLabels(ctx, del);
-
-      // get all approvals in cases of quick approve vote
-      Map<String, Short> allApprovals = approvalsByKey(current.values());
-      allApprovals.putAll(inLabels);
-
-      // get previous label votes
-      Map<String, Short> currentLabels = new HashMap<>();
-      for (Map.Entry<String, PatchSetApproval> ent : current.entrySet()) {
-        currentLabels.put(ent.getValue().getLabel(), ent.getValue().getValue());
-      }
-      Map<String, Short> previous = new HashMap<>();
-      for (Map.Entry<String, Short> ent : allApprovals.entrySet()) {
-        if (!currentLabels.containsKey(ent.getKey())) {
-          previous.put(ent.getKey(), (short)0);
-        } else {
-          previous.put(ent.getKey(), currentLabels.get(ent.getKey()));
-        }
-      }
+      LabelTypes labelTypes = ctx.getControl().getLabelTypes();
+      Map<String, Short> allApprovals = getAllApprovals(labelTypes,
+          approvalsByKey(current.values()), inLabels);
+      Map<String, Short> previous = getPreviousApprovals(allApprovals,
+          approvalsByKey(current.values()));
 
       ChangeUpdate update = ctx.getUpdate(psId);
-      LabelTypes labelTypes = ctx.getControl().getLabelTypes();
       for (Map.Entry<String, Short> ent : allApprovals.entrySet()) {
         String name = ent.getKey();
         LabelType lt = checkNotNull(labelTypes.byLabel(name), name);
@@ -607,6 +627,7 @@
         } else if (c != null && c.getValue() != ent.getValue()) {
           c.setValue(ent.getValue());
           c.setGranted(ctx.getWhen());
+          c.setTag(in.tag);
           ups.add(c);
           addLabelDelta(normName, c.getValue());
           oldApprovals.put(normName, previous.get(normName));
@@ -622,6 +643,7 @@
                   user.getAccountId(),
                   lt.getLabelId()),
               ent.getValue(), ctx.getWhen());
+          c.setTag(in.tag);
           c.setGranted(ctx.getWhen());
           ups.add(c);
           addLabelDelta(normName, c.getValue());
@@ -656,6 +678,7 @@
               ctx.getControl().getLabelTypes().getLabelTypes().get(0)
                   .getLabelId()),
               (short) 0, ctx.getWhen());
+          c.setTag(in.tag);
           c.setGranted(ctx.getWhen());
           ups.add(c);
         } else {
@@ -719,6 +742,7 @@
           user.getAccountId(),
           ctx.getWhen(),
           psId);
+      message.setTag(in.tag);
       message.setMessage(String.format(
           "Patch Set %d:%s",
           psId.get(),
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PutDraftComment.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PutDraftComment.java
index 8a1f290..647bad7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PutDraftComment.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PutDraftComment.java
@@ -119,7 +119,8 @@
         // because the input might be missing required fields. Just give up.
         throw new ResourceNotFoundException("comment not found: " + key);
       }
-      comment = maybeComment.get();
+      PatchLineComment origComment = maybeComment.get();
+      comment = new PatchLineComment(origComment);
 
       PatchSet.Id psId = comment.getKey().getParentKey().getParentKey();
       ChangeUpdate update = ctx.getUpdate(psId);
@@ -134,7 +135,7 @@
         // Delete then recreate the comment instead of an update.
 
         plcUtil.deleteComments(
-            ctx.getDb(), update, Collections.singleton(comment));
+            ctx.getDb(), update, Collections.singleton(origComment));
         comment = new PatchLineComment(
             new PatchLineComment.Key(
                 new Patch.Key(psId, in.path),
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PutTopic.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PutTopic.java
index 65fb5ae..61718ae 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PutTopic.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PutTopic.java
@@ -90,7 +90,7 @@
     private String oldTopicName;
     private String newTopicName;
 
-    public Op(Input input) {
+    Op(Input input) {
       this.input = input;
     }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/RebaseUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/RebaseUtil.java
index ae2672b..0956f9e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/RebaseUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/RebaseUtil.java
@@ -81,7 +81,7 @@
   }
 
   @AutoValue
-  static abstract class Base {
+  abstract static class Base {
     private static Base create(ChangeControl ctl, PatchSet ps) {
       if (ctl == null) {
         return null;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Revert.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Revert.java
index c4ce3c9..5f48daa 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Revert.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Revert.java
@@ -214,7 +214,7 @@
   private class SendEmailOp extends BatchUpdate.Op {
     private final ChangeInserter ins;
 
-    public SendEmailOp(ChangeInserter ins) {
+    SendEmailOp(ChangeInserter ins) {
       this.ins = ins;
     }
 
@@ -236,7 +236,7 @@
   private class PostRevertedMessageOp extends BatchUpdate.Op {
     private final ObjectId computedChangeId;
 
-    public PostRevertedMessageOp(ObjectId computedChangeId) {
+    PostRevertedMessageOp(ObjectId computedChangeId) {
       this.computedChangeId = computedChangeId;
     }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerResource.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerResource.java
index d48151b..aac9252 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerResource.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerResource.java
@@ -28,7 +28,7 @@
   public static final TypeLiteral<RestView<ReviewerResource>> REVIEWER_KIND =
       new TypeLiteral<RestView<ReviewerResource>>() {};
 
-  public static interface Factory {
+  public interface Factory {
     ReviewerResource create(ChangeResource change, Account.Id id);
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/SetHashtagsOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/SetHashtagsOp.java
index 2b0a5d9..5846400 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/SetHashtagsOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/SetHashtagsOp.java
@@ -93,7 +93,7 @@
     }
     change = ctx.getChange();
     ChangeUpdate update = ctx.getUpdate(change.currentPatchSetId());
-    ChangeNotes notes = update.getChangeNotes().load();
+    ChangeNotes notes = update.getNotes().load();
 
     Set<String> existingHashtags = notes.getHashtags();
     Set<String> updated = new HashSet<>();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java
index 0c60569..5b4e430 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java
@@ -121,6 +121,7 @@
 
     public TestSubmitInput(SubmitInput base, boolean failAfterRefUpdates) {
       this.onBehalfOf = base.onBehalfOf;
+      this.notify = base.notify;
       this.failAfterRefUpdates = failAfterRefUpdates;
     }
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
index 5a1fdc6..49f69b0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
@@ -45,6 +45,7 @@
 import com.google.gerrit.extensions.webui.PatchSetWebLink;
 import com.google.gerrit.extensions.webui.ProjectWebLink;
 import com.google.gerrit.extensions.webui.TopMenu;
+import com.google.gerrit.extensions.webui.WebUiPlugin;
 import com.google.gerrit.rules.PrologModule;
 import com.google.gerrit.rules.RulesCache;
 import com.google.gerrit.server.AnonymousUser;
@@ -309,6 +310,7 @@
     DynamicSet.setOf(binder(), BranchWebLink.class);
     DynamicMap.mapOf(binder(), OAuthLoginProvider.class);
     DynamicSet.setOf(binder(), AccountExternalIdCreator.class);
+    DynamicSet.setOf(binder(), WebUiPlugin.class);
 
     factory(UploadValidators.Factory.class);
     DynamicSet.setOf(binder(), UploadValidationListener.class);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/config/GerritServerIdProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerIdProvider.java
similarity index 94%
rename from gerrit-server/src/main/java/com/google/gerrit/server/api/config/GerritServerIdProvider.java
rename to gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerIdProvider.java
index 20ea8f0..9479438 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/config/GerritServerIdProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerIdProvider.java
@@ -12,13 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.api.config;
+package com.google.gerrit.server.config;
 
 import static java.nio.charset.StandardCharsets.UTF_8;
 
 import com.google.common.base.Strings;
-import com.google.gerrit.server.config.GerritServerConfig;
-import com.google.gerrit.server.config.SitePaths;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GetServerInfo.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GetServerInfo.java
index e5ac370..d8a3984 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GetServerInfo.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GetServerInfo.java
@@ -26,7 +26,9 @@
 import com.google.gerrit.extensions.config.DownloadScheme;
 import com.google.gerrit.extensions.registration.DynamicItem;
 import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.gerrit.extensions.restapi.RestReadView;
+import com.google.gerrit.extensions.webui.WebUiPlugin;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.AuthType;
 import com.google.gerrit.server.EnableSignedPush;
@@ -58,6 +60,7 @@
   private final DynamicMap<DownloadScheme> downloadSchemes;
   private final DynamicMap<DownloadCommand> downloadCommands;
   private final DynamicMap<CloneCommand> cloneCommands;
+  private final DynamicSet<WebUiPlugin> plugins;
   private final GetArchive.AllowedFormats archiveFormats;
   private final AllProjectsName allProjectsName;
   private final AllUsersName allUsersName;
@@ -75,6 +78,7 @@
       DynamicMap<DownloadScheme> downloadSchemes,
       DynamicMap<DownloadCommand> downloadCommands,
       DynamicMap<CloneCommand> cloneCommands,
+      DynamicSet<WebUiPlugin> webUiPlugins,
       GetArchive.AllowedFormats archiveFormats,
       AllProjectsName allProjectsName,
       AllUsersName allUsersName,
@@ -89,6 +93,7 @@
     this.downloadSchemes = downloadSchemes;
     this.downloadCommands = downloadCommands;
     this.cloneCommands = cloneCommands;
+    this.plugins = webUiPlugins;
     this.archiveFormats = archiveFormats;
     this.allProjectsName = allProjectsName;
     this.allUsersName = allUsersName;
@@ -270,6 +275,12 @@
   private PluginConfigInfo getPluginInfo() {
     PluginConfigInfo info = new PluginConfigInfo();
     info.hasAvatars = toBoolean(avatar.get() != null);
+    info.jsResourcePaths = new ArrayList<>();
+    for (WebUiPlugin u : plugins) {
+      info.jsResourcePaths.add(String.format("plugins/%s/%s",
+          u.getPluginName(),
+          u.getJavaScriptResourcePath()));
+    }
     return info;
   }
 
@@ -385,6 +396,7 @@
 
   public static class PluginConfigInfo {
     public Boolean hasAvatars;
+    public List<String> jsResourcePaths;
   }
 
   public static class SshdInfo {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitReceivePackGroupsProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitReceivePackGroupsProvider.java
index 5dd2784..49b3467 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitReceivePackGroupsProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitReceivePackGroupsProvider.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.server.config;
 
+import com.google.common.collect.ImmutableList;
 import com.google.gerrit.server.account.GroupBackend;
 import com.google.gerrit.server.group.SystemGroupBackend;
 import com.google.gerrit.server.util.ServerRequestContext;
@@ -30,8 +31,8 @@
       @GerritServerConfig Config config,
       ThreadLocalRequestContext threadContext,
       ServerRequestContext serverCtx) {
-    super(gb, threadContext, serverCtx, config.getStringList("receive", null,
-        "allowGroup"));
+    super(gb, threadContext, serverCtx, ImmutableList.copyOf(
+        config.getStringList("receive", null, "allowGroup")));
 
     // If no group was set, default to "registered users"
     //
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitUploadPackGroupsProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitUploadPackGroupsProvider.java
index 545f48b..b772089 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitUploadPackGroupsProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitUploadPackGroupsProvider.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.server.config;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.gerrit.server.account.GroupBackend;
 import com.google.gerrit.server.group.SystemGroupBackend;
@@ -29,8 +30,8 @@
       @GerritServerConfig Config config,
       ThreadLocalRequestContext threadContext,
       ServerRequestContext serverCtx) {
-    super(gb, threadContext, serverCtx, config.getStringList("upload", null,
-        "allowGroup"));
+    super(gb, threadContext, serverCtx, ImmutableList.copyOf(
+        config.getStringList("upload", null, "allowGroup")));
 
     // If no group was set, default to "registered users" and "anonymous"
     //
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitwebCgiConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitwebCgiConfig.java
index 4a58f73..830579f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitwebCgiConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitwebCgiConfig.java
@@ -53,8 +53,12 @@
 
     String cfgCgi = cfg.getString("gitweb", null, "cgi");
     Path pkgCgi = Paths.get("/usr/lib/cgi-bin/gitweb.cgi");
-    String[] resourcePaths = {"/usr/share/gitweb/static", "/usr/share/gitweb",
-        "/var/www/static", "/var/www"};
+    String[] resourcePaths = {
+        "/usr/share/gitweb/static",
+        "/usr/share/gitweb",
+        "/var/www/static",
+        "/var/www",
+    };
     Path cgi;
 
     if (cfgCgi != null) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GroupSetProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GroupSetProvider.java
index 9e55a7f..0307b7c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GroupSetProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GroupSetProvider.java
@@ -28,6 +28,7 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.List;
 import java.util.Set;
 
 public abstract class GroupSetProvider implements
@@ -40,7 +41,7 @@
   @Inject
   protected GroupSetProvider(GroupBackend groupBackend,
       ThreadLocalRequestContext threadContext,
-      ServerRequestContext serverCtx, String[] groupNames) {
+      ServerRequestContext serverCtx, List<String> groupNames) {
     RequestContext ctx = threadContext.setContext(serverCtx);
     try {
       ImmutableSet.Builder<AccountGroup.UUID> builder = ImmutableSet.builder();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/ListCaches.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/ListCaches.java
index 653f5bd..4183e61 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/ListCaches.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/ListCaches.java
@@ -41,7 +41,7 @@
 public class ListCaches implements RestReadView<ConfigResource> {
   private final DynamicMap<Cache<?, ?>> cacheMap;
 
-  public static enum OutputFormat {
+  public enum OutputFormat {
     LIST, TEXT_LIST
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/PostCaches.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/PostCaches.java
index 5178210..33a458e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/PostCaches.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/PostCaches.java
@@ -52,7 +52,7 @@
     }
   }
 
-  public static enum Operation {
+  public enum Operation {
     FLUSH_ALL, FLUSH
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/RepositoryConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/RepositoryConfig.java
index 13188dc..e250395 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/RepositoryConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/RepositoryConfig.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.server.config;
 
+import com.google.common.collect.ImmutableList;
 import com.google.gerrit.extensions.client.SubmitType;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.inject.Inject;
@@ -46,9 +47,9 @@
         DEFAULT_SUBMIT_TYPE_NAME, SubmitType.MERGE_IF_NECESSARY);
   }
 
-  public String[] getOwnerGroups(Project.NameKey project) {
-    return cfg.getStringList(SECTION_NAME, findSubSection(project.get()),
-        OWNER_GROUP_NAME);
+  public List<String> getOwnerGroups(Project.NameKey project) {
+    return ImmutableList.copyOf(cfg.getStringList(SECTION_NAME,
+        findSubSection(project.get()), OWNER_GROUP_NAME));
   }
 
   public Path getBasePath(Project.NameKey project) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/TrackingFooters.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/TrackingFooters.java
index 6fbc206..672c461 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/TrackingFooters.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/TrackingFooters.java
@@ -39,6 +39,10 @@
 
   public Multimap<String, String> extract(List<FooterLine> lines) {
     Multimap<String, String> r = ArrayListMultimap.create();
+    if (lines == null) {
+      return r;
+    }
+
     for (FooterLine footer : lines) {
       for (TrackingFooter config : trackingFooters) {
         if (footer.matches(config.footerKey())) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditModifier.java b/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditModifier.java
index 1528751..0cd80f2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditModifier.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditModifier.java
@@ -82,7 +82,7 @@
 @Singleton
 public class ChangeEditModifier {
 
-  private static enum TreeOperation {
+  private enum TreeOperation {
     CHANGE_ENTRY,
     DELETE_ENTRY,
     RENAME_ENTRY,
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditUtil.java
index b8e6093..bfa3188 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditUtil.java
@@ -147,7 +147,7 @@
       int n = change.currentPatchSetId().get();
       String[] refNames = new String[n];
       for (int i = n; i > 0; i--) {
-        refNames[i-1] = RefNames.refsEdit(
+        refNames[i - 1] = RefNames.refsEdit(
             u.getAccountId(), change.getId(),
             new PatchSet.Id(change.getId(), i));
       }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/events/EventFactory.java b/gerrit-server/src/main/java/com/google/gerrit/server/events/EventFactory.java
index 50d02df..5807c26 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/events/EventFactory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/events/EventFactory.java
@@ -244,7 +244,7 @@
         SubmitLabelAttribute la = new SubmitLabelAttribute();
         la.label = lbl.label;
         la.status = lbl.status.name();
-        if(lbl.appliedBy != null) {
+        if (lbl.appliedBy != null) {
           Account a = accountCache.get(lbl.appliedBy).getAccount();
           la.by = asAccountAttribute(a);
         }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/BatchUpdate.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/BatchUpdate.java
index e9ad8b7..e32e6ad 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/BatchUpdate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/BatchUpdate.java
@@ -100,7 +100,7 @@
   }
 
   /** Order of execution of the various phases. */
-  public static enum Order {
+  public enum Order {
     /**
      * Update the repository and execute all ref updates before touching the
      * database.
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/DestinationList.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/DestinationList.java
index ca1f705c..7c02e5b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/DestinationList.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/DestinationList.java
@@ -53,7 +53,7 @@
 
   protected static Set<Branch.NameKey> toSet(List<Row> destRows) {
     Set<Branch.NameKey> dests = Sets.newHashSetWithExpectedSize(destRows.size());
-    for(Row row : destRows) {
+    for (Row row : destRows) {
       dests.add(new Branch.NameKey(new Project.NameKey(row.right), row.left));
     }
     return dests;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/EmailMerge.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/EmailMerge.java
index f90b72c..d236682 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/EmailMerge.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/EmailMerge.java
@@ -15,6 +15,7 @@
 package com.google.gerrit.server.git;
 
 import com.google.gerrit.common.Nullable;
+import com.google.gerrit.extensions.api.changes.ReviewInput.NotifyHandling;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.Project;
@@ -42,7 +43,7 @@
 
   public interface Factory {
     EmailMerge create(Project.NameKey project, Change.Id changeId,
-        Account.Id submitter);
+        Account.Id submitter, NotifyHandling notifyHandling);
   }
 
   private final ExecutorService sendEmailsExecutor;
@@ -54,6 +55,7 @@
   private final Project.NameKey project;
   private final Change.Id changeId;
   private final Account.Id submitter;
+  private final NotifyHandling notifyHandling;
   private ReviewDb db;
 
   @Inject
@@ -64,7 +66,8 @@
       IdentifiedUser.GenericFactory identifiedUserFactory,
       @Assisted Project.NameKey project,
       @Assisted Change.Id changeId,
-      @Assisted @Nullable Account.Id submitter) {
+      @Assisted @Nullable Account.Id submitter,
+      @Assisted NotifyHandling notifyHandling) {
     this.sendEmailsExecutor = executor;
     this.mergedSenderFactory = mergedSenderFactory;
     this.schemaFactory = schemaFactory;
@@ -73,6 +76,7 @@
     this.project = project;
     this.changeId = changeId;
     this.submitter = submitter;
+    this.notifyHandling = notifyHandling;
   }
 
   public void sendAsync() {
@@ -87,6 +91,7 @@
       if (submitter != null) {
         cm.setFrom(submitter);
       }
+      cm.setNotify(notifyHandling);
       cm.send();
     } catch (Exception e) {
       log.error("Cannot email merged notification for " + changeId, e);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/GitRepositoryManager.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/GitRepositoryManager.java
index ab6d66c..29e14ec 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/GitRepositoryManager.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/GitRepositoryManager.java
@@ -46,9 +46,6 @@
 
   /**
    * Create (and open) a repository by name.
-   * <p>
-   * If the implementation supports separate metadata repositories, this method
-   * must also create the metadata repository, but does not open it.
    *
    * @param name the repository name, relative to the base directory.
    * @return the cached Repository instance. Caller must call {@code close()}
@@ -62,23 +59,6 @@
       throws RepositoryCaseMismatchException, RepositoryNotFoundException,
       IOException;
 
-  /**
-   * Open the repository storing metadata for the given project.
-   * <p>
-   * This includes any project-specific metadata <em>except</em> what is stored
-   * in {@code refs/meta/config}. Implementations may choose to store all
-   * metadata in the original project.
-   *
-   * @param name the base project name name.
-   * @return the cached metadata Repository instance. Caller must call
-   *         {@code close()} when done to decrement the resource handle.
-   * @throws RepositoryNotFoundException the name does not denote an existing
-   *         repository.
-   * @throws IOException the name cannot be read as a repository.
-   */
-  Repository openMetadataRepository(Project.NameKey name)
-      throws RepositoryNotFoundException, IOException;
-
   /** @return set of all known projects, sorted by natural NameKey order. */
   SortedSet<Project.NameKey> list();
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/GroupCollector.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/GroupCollector.java
index 8f9add5..d832260 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/GroupCollector.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/GroupCollector.java
@@ -103,7 +103,7 @@
     return rsrc.getPatchSet().getGroups();
   }
 
-  private static interface Lookup {
+  private interface Lookup {
     List<String> lookup(PatchSet.Id psId)
         throws OrmException, NoSuchChangeException;
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/GroupList.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/GroupList.java
index 1477f6a..f4a03cf 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/GroupList.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/GroupList.java
@@ -39,7 +39,7 @@
     List<Row> rows = parse(text, FILE_NAME, TRIM, TRIM, errors);
     Map<AccountGroup.UUID, GroupReference> groupsByUUID =
         new HashMap<>(rows.size());
-    for(Row row : rows) {
+    for (Row row : rows) {
       AccountGroup.UUID uuid = new AccountGroup.UUID(row.left);
       String name = row.right;
       GroupReference ref = new GroupReference(uuid, name);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
index e0c4c74..da9cf1d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
@@ -14,16 +14,12 @@
 
 package com.google.gerrit.server.git;
 
-import static com.google.common.base.Preconditions.checkState;
-
-import com.google.common.base.MoreObjects;
 import com.google.gerrit.extensions.events.LifecycleListener;
 import com.google.gerrit.lifecycle.LifecycleModule;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.client.RefNames;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.SitePaths;
-import com.google.gerrit.server.notedb.NotesMigration;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
@@ -124,23 +120,17 @@
   }
 
   private final Path basePath;
-  private final NotesMigration notesMigration;
-  private final Path noteDbPath;
   private final Lock namesUpdateLock;
   private volatile SortedSet<Project.NameKey> names = new TreeSet<>();
 
   @Inject
   LocalDiskRepositoryManager(SitePaths site,
-      @GerritServerConfig Config cfg,
-      NotesMigration notesMigration) {
-    this.notesMigration = notesMigration;
+      @GerritServerConfig Config cfg) {
     basePath = site.resolve(cfg.getString("gerrit", null, "basePath"));
     if (basePath == null) {
       throw new IllegalStateException("gerrit.basePath must be configured");
     }
 
-    noteDbPath = site.resolve(MoreObjects.firstNonNull(
-        cfg.getString("gerrit", null, "noteDbPath"), "notedb"));
     namesUpdateLock = new ReentrantLock(true /* fair */);
   }
 
@@ -213,15 +203,7 @@
   @Override
   public Repository createRepository(Project.NameKey name)
       throws RepositoryNotFoundException, RepositoryCaseMismatchException {
-    Repository repo = createRepository(getBasePath(name), name);
-    if (notesMigration.writeChanges() && !noteDbPath.equals(basePath)) {
-      createRepository(noteDbPath, name);
-    }
-    return repo;
-  }
-
-  private Repository createRepository(Path path, Project.NameKey name)
-      throws RepositoryNotFoundException, RepositoryCaseMismatchException {
+    Path path = getBasePath(name);
     if (isUnreasonableName(name)) {
       throw new RepositoryNotFoundException("Invalid name: " + name);
     }
@@ -276,17 +258,6 @@
     }
   }
 
-  @Override
-  public Repository openMetadataRepository(Project.NameKey name)
-      throws RepositoryNotFoundException, IOException {
-    checkState(notesMigration.readChanges(), "NoteDb disabled");
-    try {
-      return openRepository(noteDbPath, name);
-    } catch (RepositoryNotFoundException e) {
-      return createRepository(noteDbPath, name);
-    }
-  }
-
   private void onCreateProject(final Project.NameKey newProjectName) {
     namesUpdateLock.lock();
     try {
@@ -362,7 +333,7 @@
     final String name = nameKey.get();
 
     return name.length() == 0  // no empty paths
-      || name.charAt(name.length() -1) == '/' // no suffix
+      || name.charAt(name.length() - 1) == '/' // no suffix
       || name.indexOf('\\') >= 0 // no windows/dos style paths
       || name.charAt(0) == '/' // no absolute paths
       || new File(name).isAbsolute() // no absolute paths
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
index 07aa892..0047260 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
@@ -676,7 +676,7 @@
       CodeReviewCommit branchTip) throws IntegrationException {
     return submitStrategyFactory.create(submitType, db, or.repo, or.rw, or.ins,
         or.canMergeFlag, getAlreadyAccepted(or, branchTip), destBranch, caller,
-        mergeTip, commits, submissionId);
+        mergeTip, commits, submissionId, submitInput.notify);
   }
 
   private Set<RevCommit> getAlreadyAccepted(OpenRepo or,
@@ -706,7 +706,7 @@
   }
 
   @AutoValue
-  static abstract class BranchBatch {
+  abstract static class BranchBatch {
     @Nullable abstract SubmitType submitType();
     abstract List<ChangeData> changes();
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeUtil.java
index 4a2eee4..e832483 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeUtil.java
@@ -106,7 +106,7 @@
         : MergeStrategy.RESOLVE;
   }
 
-  public static interface Factory {
+  public interface Factory {
     MergeUtil create(ProjectState project);
     MergeUtil create(ProjectState project, boolean useContentMerge);
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MultiBaseLocalDiskRepositoryManager.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MultiBaseLocalDiskRepositoryManager.java
index dc72665..dffcf30 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MultiBaseLocalDiskRepositoryManager.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MultiBaseLocalDiskRepositoryManager.java
@@ -21,7 +21,6 @@
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.RepositoryConfig;
 import com.google.gerrit.server.config.SitePaths;
-import com.google.gerrit.server.notedb.NotesMigration;
 import com.google.inject.Inject;
 
 import org.eclipse.jgit.lib.Config;
@@ -48,9 +47,8 @@
   @Inject
   MultiBaseLocalDiskRepositoryManager(SitePaths site,
       @GerritServerConfig Config cfg,
-      NotesMigration notesMigration,
       RepositoryConfig config) {
-    super(site, cfg, notesMigration);
+    super(site, cfg);
     this.config = config;
 
     for (Path alternateBasePath : config.getAllBasePaths()) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/NotifyConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/NotifyConfig.java
index abc53f4..f88c2ce 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/NotifyConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/NotifyConfig.java
@@ -24,7 +24,7 @@
 import java.util.Set;
 
 public class NotifyConfig implements Comparable<NotifyConfig> {
-  public static enum Header {
+  public enum Header {
     TO, CC, BCC
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/QueueProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/QueueProvider.java
index cd37c9e..06b87f2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/QueueProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/QueueProvider.java
@@ -15,7 +15,7 @@
 package com.google.gerrit.server.git;
 
 public interface QueueProvider {
-  public static enum QueueType {
+  enum QueueType {
     INTERACTIVE, BATCH
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
index c81ff83..efa6174 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
@@ -63,6 +63,7 @@
 import com.google.gerrit.common.data.PermissionRule;
 import com.google.gerrit.extensions.api.changes.HashtagsInput;
 import com.google.gerrit.extensions.api.changes.ReviewInput.NotifyHandling;
+import com.google.gerrit.extensions.api.changes.SubmitInput;
 import com.google.gerrit.extensions.registration.DynamicMap;
 import com.google.gerrit.extensions.registration.DynamicMap.Entry;
 import com.google.gerrit.extensions.registration.DynamicSet;
@@ -193,6 +194,11 @@
       "Please read the documentation and contact an administrator\n"
           + "if you feel the configuration is incorrect";
 
+  private static final String SAME_CHANGE_ID_IN_MULTIPLE_CHANGES =
+      "same Change-Id in multiple changes.\n"
+          + "Squash the commits with the same Change-Id or "
+          + "ensure Change-Ids are unique for each commit";
+
   private enum Error {
         CONFIG_UPDATE("You are not allowed to perform this operation.\n"
         + "Configuration changes can only be pushed by project owners\n"
@@ -691,7 +697,8 @@
       addMessage("");
       addMessage("New Changes:");
       for (CreateRequest c : created) {
-        addMessage(formatChangeUrl(canonicalWebUrl, c.change, false));
+        addMessage(formatChangeUrl(canonicalWebUrl, c.change,
+            c.change.getSubject(), false));
       }
       addMessage("");
     }
@@ -716,20 +723,21 @@
       addMessage("Updated Changes:");
       boolean edit = magicBranch != null && magicBranch.edit;
       for (ReplaceRequest u : updated) {
-        addMessage(formatChangeUrl(canonicalWebUrl, u.change, edit));
+        addMessage(formatChangeUrl(canonicalWebUrl, u.change,
+            u.info.getSubject(), edit));
       }
       addMessage("");
     }
   }
 
   private static String formatChangeUrl(String url, Change change,
-      boolean edit) {
+      String subject, boolean edit) {
     StringBuilder m = new StringBuilder()
         .append("  ")
         .append(url)
         .append(change.getChangeId())
         .append(" ")
-        .append(ChangeUtil.cropSubject(change.getSubject()));
+        .append(ChangeUtil.cropSubject(subject));
     if (change.getStatus() == Change.Status.DRAFT) {
       m.append(" [DRAFT]");
     }
@@ -1590,7 +1598,7 @@
 
       for (ChangeLookup p : pending) {
         if (newChangeIds.contains(p.changeKey)) {
-          reject(magicBranch.cmd, "squash commits first");
+          reject(magicBranch.cmd, SAME_CHANGE_ID_IN_MULTIPLE_CHANGES);
           newChanges = Collections.emptyList();
           return;
         }
@@ -1807,7 +1815,7 @@
     RevisionResource rsrc = new RevisionResource(changes.parse(changeCtl), ps);
     try (MergeOp op = mergeOpProvider.get()) {
       op.merge(db, rsrc.getChange(),
-          changeCtl.getUser().asIdentifiedUser(), false, null);
+          changeCtl.getUser().asIdentifiedUser(), false, new SubmitInput());
     }
     addMessage("");
     Change c = notesFactory
@@ -1991,7 +1999,7 @@
         // very common error due to users making a new commit rather than
         // amending when trying to address review comments.
         if (rp.getRevWalk().isMergedInto(prior, newCommit)) {
-          reject(inputCommand, "squash commits first");
+          reject(inputCommand, SAME_CHANGE_ID_IN_MULTIPLE_CHANGES);
           return false;
         }
       }
@@ -2051,7 +2059,7 @@
       try {
         edit = editUtil.byChange(changeCtl);
       } catch (AuthException | IOException e) {
-        log.error("Cannt retrieve edit", e);
+        log.error("Cannot retrieve edit", e);
         return false;
       }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReplaceOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReplaceOp.java
index e778735..9e51b3f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReplaceOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReplaceOp.java
@@ -380,7 +380,7 @@
       hooks.doChangeMergedHook(change, account, newPatchSet, ctx.getDb(),
           commit.getName());
     }
-    try{
+    try {
       runHook(ctx);
     } catch (Exception e) {
       log.warn("ChangeHook.doCommentAddedHook delivery failed", e);
@@ -403,7 +403,7 @@
     List<LabelType> labels = changeControl.getLabelTypes().getLabelTypes();
     Map<String, Short> allApprovals = new HashMap<>();
     Map<String, Short> oldApprovals = new HashMap<>();
-    for (LabelType lt : labels){
+    for (LabelType lt : labels) {
       allApprovals.put(lt.getName(), (short) 0);
       oldApprovals.put(lt.getName(), null);
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java
index bd8c156..e2ec146 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java
@@ -147,7 +147,7 @@
         ret.addAll(m.subscribedTo(branch));
       }
     }
-    logDebug("Calculated superprojects for " + branch + " are "+ ret);
+    logDebug("Calculated superprojects for " + branch + " are " + ret);
     return ret;
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java
index 954e412..a0c9312 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java
@@ -262,7 +262,7 @@
      * <li>{@link #DONE}: finished executing, if not periodic.</li>
      * </ol>
      */
-    public static enum State {
+    public enum State {
       // Ordered like this so ordinal matches the order we would
       // prefer to see tasks sorted in: done before running,
       // running before ready, ready before sleeping.
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/CommitMergeStatus.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/CommitMergeStatus.java
index 1102357..bb9d359 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/CommitMergeStatus.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/CommitMergeStatus.java
@@ -59,7 +59,7 @@
 
   private String message;
 
-  private CommitMergeStatus(String message) {
+  CommitMergeStatus(String message) {
     this.message = message;
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/RebaseIfNecessary.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/RebaseIfNecessary.java
index 6c7a4c4..4d51aea 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/RebaseIfNecessary.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/RebaseIfNecessary.java
@@ -34,7 +34,6 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.List;
 
 public class RebaseIfNecessary extends SubmitStrategy {
@@ -204,10 +203,8 @@
   private List<CodeReviewCommit> sort(Collection<CodeReviewCommit> toSort)
       throws IntegrationException {
     try {
-      List<CodeReviewCommit> result = new RebaseSorter(
+      return new RebaseSorter(
           args.rw, args.alreadyAccepted, args.canMergeFlag).sort(toSort);
-      Collections.sort(result, CodeReviewCommit.ORDER);
-      return result;
     } catch (IOException e) {
       throw new IntegrationException("Commit sorting failed", e);
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/SubmitStrategy.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/SubmitStrategy.java
index 63f5963..60662fe 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/SubmitStrategy.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/SubmitStrategy.java
@@ -18,6 +18,7 @@
 
 import com.google.common.collect.Sets;
 import com.google.gerrit.common.ChangeHooks;
+import com.google.gerrit.extensions.api.changes.ReviewInput.NotifyHandling;
 import com.google.gerrit.extensions.client.SubmitType;
 import com.google.gerrit.extensions.config.FactoryModule;
 import com.google.gerrit.reviewdb.client.Branch;
@@ -89,7 +90,8 @@
           RevFlag canMergeFlag,
           ReviewDb db,
           Set<RevCommit> alreadyAccepted,
-          String submissionId);
+          String submissionId,
+          NotifyHandling notifyHandling);
     }
 
     final AccountCache accountCache;
@@ -120,6 +122,7 @@
     final Set<RevCommit> alreadyAccepted;
     final String submissionId;
     final SubmitType submitType;
+    final NotifyHandling notifyHandling;
 
     final ProjectState project;
     final MergeSorter mergeSorter;
@@ -154,7 +157,8 @@
         @Assisted ReviewDb db,
         @Assisted Set<RevCommit> alreadyAccepted,
         @Assisted String submissionId,
-        @Assisted SubmitType submitType) {
+        @Assisted SubmitType submitType,
+        @Assisted NotifyHandling notifyHandling) {
       this.accountCache = accountCache;
       this.approvalsUtil = approvalsUtil;
       this.batchUpdateFactory = batchUpdateFactory;
@@ -183,6 +187,7 @@
       this.alreadyAccepted = alreadyAccepted;
       this.submissionId = submissionId;
       this.submitType = submitType;
+      this.notifyHandling = notifyHandling;
 
       this.project = checkNotNull(projectCache.get(destBranch.getParentKey()),
             "project not found: %s", destBranch.getParentKey());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/SubmitStrategyFactory.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/SubmitStrategyFactory.java
index e9e060c..ce34a53 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/SubmitStrategyFactory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/SubmitStrategyFactory.java
@@ -15,6 +15,7 @@
 package com.google.gerrit.server.git.strategy;
 
 import com.google.gerrit.extensions.client.SubmitType;
+import com.google.gerrit.extensions.api.changes.ReviewInput.NotifyHandling;
 import com.google.gerrit.reviewdb.client.Branch;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
@@ -51,11 +52,11 @@
       Repository repo, CodeReviewRevWalk rw, ObjectInserter inserter,
       RevFlag canMergeFlag, Set<RevCommit> alreadyAccepted,
       Branch.NameKey destBranch, IdentifiedUser caller, MergeTip mergeTip,
-      CommitStatus commits, String submissionId)
+      CommitStatus commits, String submissionId, NotifyHandling notifyHandling)
       throws IntegrationException {
     SubmitStrategy.Arguments args = argsFactory.create(submitType, destBranch,
         commits, rw, caller, mergeTip, inserter, repo, canMergeFlag, db,
-        alreadyAccepted, submissionId);
+        alreadyAccepted, submissionId, notifyHandling);
     switch (submitType) {
       case CHERRY_PICK:
         return new CherryPick(args);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/SubmitStrategyOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/SubmitStrategyOp.java
index 8f15c44..f886e49 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/SubmitStrategyOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/SubmitStrategyOp.java
@@ -518,7 +518,8 @@
     // have failed fast in one of the other steps.
     try {
       args.mergedSenderFactory
-          .create(ctx.getProject(), getId(), submitter.getAccountId())
+          .create(ctx.getProject(), getId(), submitter.getAccountId(),
+              args.notifyHandling)
           .sendAsync();
     } catch (Exception e) {
       log.error("Cannot email merged notification for " + getId(), e);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/validators/CommitValidators.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/validators/CommitValidators.java
index b069ca9..5e84fd3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/validators/CommitValidators.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/validators/CommitValidators.java
@@ -66,7 +66,7 @@
   private static final Logger log = LoggerFactory
       .getLogger(CommitValidators.class);
 
-  public static enum Policy {
+  public enum Policy {
     /** Use {@link #validateForGerritCommits}. */
     GERRIT,
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/CreateGroup.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/CreateGroup.java
index f3f12a1..dbcad99 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/CreateGroup.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/CreateGroup.java
@@ -56,7 +56,7 @@
 
 @RequiresCapability(GlobalCapability.CREATE_GROUP)
 public class CreateGroup implements RestModifyView<TopLevelResource, GroupInput> {
-  public static interface Factory {
+  public interface Factory {
     CreateGroup create(@Assisted String name);
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/DbGroupMemberAuditListener.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/DbGroupMemberAuditListener.java
index bc8bff7..f97dac7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/DbGroupMemberAuditListener.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/DbGroupMemberAuditListener.java
@@ -49,7 +49,7 @@
   private final UniversalGroupBackend groupBackend;
 
   @Inject
-  public DbGroupMemberAuditListener(SchemaFactory<ReviewDb> schema,
+  DbGroupMemberAuditListener(SchemaFactory<ReviewDb> schema,
       AccountCache accountCache, GroupCache groupCache,
       UniversalGroupBackend groupBackend) {
     this.schema = schema;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/GroupsCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/GroupsCollection.java
index 4636c2f..6268d72 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/GroupsCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/GroupsCollection.java
@@ -69,7 +69,7 @@
     final CurrentUser user = self.get();
     if (user instanceof AnonymousUser) {
       throw new AuthException("Authentication required");
-    } else if(!(user.isIdentifiedUser())) {
+    } else if (!(user.isIdentifiedUser())) {
       throw new ResourceNotFoundException();
     }
 
@@ -82,7 +82,7 @@
     final CurrentUser user = self.get();
     if (user instanceof AnonymousUser) {
       throw new AuthException("Authentication required");
-    } else if(!(user.isIdentifiedUser())) {
+    } else if (!(user.isIdentifiedUser())) {
       throw new ResourceNotFoundException(id);
     }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java
index 1b1ddbf..40db33b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java
@@ -66,7 +66,7 @@
   private final GroupControl.GenericFactory genericGroupControlFactory;
   private final Provider<IdentifiedUser> identifiedUser;
   private final IdentifiedUser.GenericFactory userFactory;
-  private final Provider<GetGroups> accountGetGroups;
+  private final GetGroups accountGetGroups;
   private final GroupJson json;
   private final GroupBackend groupBackend;
 
@@ -149,7 +149,8 @@
       final GroupControl.GenericFactory genericGroupControlFactory,
       final Provider<IdentifiedUser> identifiedUser,
       final IdentifiedUser.GenericFactory userFactory,
-      final Provider<GetGroups> accountGetGroups, GroupJson json,
+      final GetGroups accountGetGroups,
+      GroupJson json,
       GroupBackend groupBackend) {
     this.groupCache = groupCache;
     this.groupControlFactory = groupControlFactory;
@@ -197,7 +198,7 @@
     }
 
     if (user != null) {
-      return accountGetGroups.get().apply(
+      return accountGetGroups.apply(
           new AccountResource(userFactory.create(user)));
     }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/SchemaUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/SchemaUtil.java
index 53ff0e3..5ead80f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/SchemaUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/SchemaUtil.java
@@ -73,6 +73,16 @@
   }
 
   @SafeVarargs
+  public static <V> Schema<V> schema(Schema<V> schema,
+      FieldDef<V, ?>... moreFields) {
+    return new Schema<>(
+        new ImmutableList.Builder<FieldDef<V, ?>>()
+            .addAll(schema.getFields().values())
+            .addAll(ImmutableList.copyOf(moreFields))
+            .build());
+  }
+
+  @SafeVarargs
   public static <V> Schema<V> schema(FieldDef<V, ?>... fields) {
     return schema(ImmutableList.copyOf(fields));
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/change/AllChangesIndexer.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/AllChangesIndexer.java
index a38b1e7..b4d01bb 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/change/AllChangesIndexer.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/AllChangesIndexer.java
@@ -39,7 +39,7 @@
 import com.google.gerrit.server.index.IndexExecutor;
 import com.google.gerrit.server.index.SiteIndexer;
 import com.google.gerrit.server.notedb.ChangeNotes;
-import com.google.gerrit.server.patch.PatchListLoader;
+import com.google.gerrit.server.patch.AutoMerger;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gwtorm.server.SchemaFactory;
@@ -90,6 +90,7 @@
   private final ChangeNotes.Factory notesFactory;
   private final ProjectCache projectCache;
   private final ThreeWayMergeStrategy mergeStrategy;
+  private final AutoMerger autoMerger;
 
   @Inject
   AllChangesIndexer(SchemaFactory<ReviewDb> schemaFactory,
@@ -99,7 +100,8 @@
       ChangeIndexer.Factory indexerFactory,
       ChangeNotes.Factory notesFactory,
       @GerritServerConfig Config config,
-      ProjectCache projectCache) {
+      ProjectCache projectCache,
+      AutoMerger autoMerger) {
     this.schemaFactory = schemaFactory;
     this.changeDataFactory = changeDataFactory;
     this.repoManager = repoManager;
@@ -108,6 +110,7 @@
     this.notesFactory = notesFactory;
     this.projectCache = projectCache;
     this.mergeStrategy = MergeUtil.getMergeStrategy(config);
+    this.autoMerger = autoMerger;
   }
 
   @Override
@@ -236,6 +239,7 @@
           }
           new ProjectIndexer(indexer,
               mergeStrategy,
+              autoMerger,
               byId,
               repo,
               done,
@@ -257,6 +261,7 @@
   private static class ProjectIndexer implements Callable<Void> {
     private final ChangeIndexer indexer;
     private final ThreeWayMergeStrategy mergeStrategy;
+    private final AutoMerger autoMerger;
     private final Multimap<ObjectId, ChangeData> byId;
     private final ProgressMonitor done;
     private final ProgressMonitor failed;
@@ -266,6 +271,7 @@
 
     private ProjectIndexer(ChangeIndexer indexer,
         ThreeWayMergeStrategy mergeStrategy,
+        AutoMerger autoMerger,
         Multimap<ObjectId, ChangeData> changesByCommitId,
         Repository repo,
         ProgressMonitor done,
@@ -273,6 +279,7 @@
         PrintWriter verboseWriter) {
       this.indexer = indexer;
       this.mergeStrategy = mergeStrategy;
+      this.autoMerger = autoMerger;
       this.byId = changesByCommitId;
       this.repo = repo;
       this.done = done;
@@ -366,7 +373,8 @@
           walk.parseBody(a);
           return walk.parseTree(a.getTree());
         case 2:
-          return PatchListLoader.automerge(repo, walk, b, mergeStrategy);
+          RevCommit am = autoMerger.merge(repo, walk, b, mergeStrategy);
+          return am == null ? null : am.getTree();
         default:
           return null;
       }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeField.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeField.java
index fdeb654..67694ac 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeField.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeField.java
@@ -576,6 +576,23 @@
         }
       };
 
+  /** Users who have starred this change. */
+  public static final FieldDef<ChangeData, Iterable<Integer>> STARREDBY =
+      new FieldDef.Repeatable<ChangeData, Integer>(
+          ChangeQueryBuilder.FIELD_STARREDBY, FieldType.INTEGER, true) {
+        @Override
+        public Iterable<Integer> get(ChangeData input, FillArgs args)
+            throws OrmException {
+          return Iterables.transform(input.starredBy(),
+              new Function<Account.Id, Integer>() {
+            @Override
+            public Integer apply(Account.Id accountId) {
+              return accountId.get();
+            }
+          });
+        }
+      };
+
   /** Opaque group identifiers for this change's patch sets. */
   public static final FieldDef<ChangeData, Iterable<String>> GROUP =
       new FieldDef.Repeatable<ChangeData, String>(
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeIndexer.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeIndexer.java
index 48df562..0ca9922 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeIndexer.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeIndexer.java
@@ -186,14 +186,26 @@
   /**
    * Synchronously index a change.
    *
-   * @param change change to index.
    * @param db review database.
+   * @param change change to index.
    */
   public void index(ReviewDb db, Change change) throws IOException {
     index(changeDataFactory.create(db, change));
   }
 
   /**
+   * Synchronously index a change.
+   *
+   * @param db review database.
+   * @param project the project to which the change belongs.
+   * @param changeId ID of the change to index.
+   */
+  public void index(ReviewDb db, Project.NameKey project, Change.Id changeId)
+      throws IOException {
+    index(changeDataFactory.create(db, project, changeId));
+  }
+
+  /**
    * Start deleting a change.
    *
    * @param id change to delete.
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java
index b39a0b7..9fbe51f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java
@@ -59,45 +59,13 @@
       ChangeField.COMMITTER);
 
   @Deprecated
-  static final Schema<ChangeData> V26 = schema(
-      ChangeField.LEGACY_ID,
-      ChangeField.ID,
-      ChangeField.STATUS,
-      ChangeField.PROJECT,
-      ChangeField.PROJECTS,
-      ChangeField.REF,
-      ChangeField.EXACT_TOPIC,
-      ChangeField.FUZZY_TOPIC,
-      ChangeField.UPDATED,
-      ChangeField.FILE_PART,
-      ChangeField.PATH,
-      ChangeField.OWNER,
-      ChangeField.REVIEWER,
-      ChangeField.COMMIT,
-      ChangeField.TR,
-      ChangeField.LABEL,
-      ChangeField.COMMIT_MESSAGE,
-      ChangeField.COMMENT,
-      ChangeField.CHANGE,
-      ChangeField.APPROVAL,
-      ChangeField.MERGEABLE,
-      ChangeField.ADDED,
-      ChangeField.DELETED,
-      ChangeField.DELTA,
-      ChangeField.HASHTAG,
-      ChangeField.COMMENTBY,
-      ChangeField.PATCH_SET,
-      ChangeField.GROUP,
-      ChangeField.SUBMISSIONID,
-      ChangeField.EDITBY,
-      ChangeField.REVIEWEDBY,
-      ChangeField.EXACT_COMMIT,
-      ChangeField.AUTHOR,
-      ChangeField.COMMITTER,
-      ChangeField.DRAFTBY);
+  static final Schema<ChangeData> V26 = schema(V25, ChangeField.DRAFTBY);
 
+  @Deprecated
   static final Schema<ChangeData> V27 = schema(V26.getFields().values());
 
+  static final Schema<ChangeData> V28 = schema(V27, ChangeField.STARREDBY);
+
   public static final ChangeSchemaDefinitions INSTANCE =
       new ChangeSchemaDefinitions();
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/AbandonedSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/AbandonedSender.java
index dbd0438..1e8bdf4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/AbandonedSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/AbandonedSender.java
@@ -24,7 +24,7 @@
 
 /** Send notice about a change being abandoned by its owner. */
 public class AbandonedSender extends ReplyToChangeSender {
-  public static interface Factory extends
+  public interface Factory extends
       ReplyToChangeSender.Factory<AbandonedSender> {
     @Override
     AbandonedSender create(Project.NameKey project, Change.Id change);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/AddReviewerSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/AddReviewerSender.java
index 98fc4a0..c9e42ad 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/AddReviewerSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/AddReviewerSender.java
@@ -23,7 +23,7 @@
 
 /** Asks a user to review a change. */
 public class AddReviewerSender extends NewChangeSender {
-  public static interface Factory {
+  public interface Factory {
     AddReviewerSender create(Project.NameKey project, Change.Id id);
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java
index b244ec4..4e1891a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java
@@ -33,6 +33,7 @@
 import com.google.gerrit.server.patch.PatchListEntry;
 import com.google.gerrit.server.patch.PatchListNotAvailableException;
 import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
+import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.project.ProjectState;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gwtorm.server.OrmException;
@@ -305,10 +306,10 @@
       // BCC anyone who has starred this change.
       //
       for (Account.Id accountId : args.starredChangesUtil
-          .byChange(change.getId())) {
+          .byChangeFromIndex(change.getId())) {
         super.add(RecipientType.BCC, accountId);
       }
-    } catch (OrmException err) {
+    } catch (OrmException | NoSuchChangeException err) {
       // Just don't BCC everyone. Better to send a partial message to those
       // we already have queued up then to fail deliver entirely to people
       // who have a lower interest in the change.
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java
index c845c28..a39e43a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java
@@ -52,7 +52,7 @@
   private static final Logger log = LoggerFactory
       .getLogger(CommentSender.class);
 
-  public static interface Factory {
+  public interface Factory {
     CommentSender create(Project.NameKey project, Change.Id id);
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CreateChangeSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CreateChangeSender.java
index 87bfa37..2110e37 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CreateChangeSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CreateChangeSender.java
@@ -33,7 +33,7 @@
   private static final Logger log =
       LoggerFactory.getLogger(CreateChangeSender.class);
 
-  public static interface Factory {
+  public interface Factory {
     CreateChangeSender create(Project.NameKey project, Change.Id id);
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/DeleteVoteSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/DeleteVoteSender.java
index 05937d5..d861109 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/DeleteVoteSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/DeleteVoteSender.java
@@ -24,7 +24,7 @@
 
 /** Send notice about a vote that was removed from a change. */
 public class DeleteVoteSender extends ReplyToChangeSender {
-  public static interface Factory extends
+  public interface Factory extends
       ReplyToChangeSender.Factory<DeleteVoteSender> {
     @Override
     DeleteVoteSender create(Project.NameKey project, Change.Id change);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailTokenVerifier.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailTokenVerifier.java
index b6fb006..41e1e2c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailTokenVerifier.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailTokenVerifier.java
@@ -39,7 +39,7 @@
   ParsedToken decode(String tokenString) throws InvalidTokenException;
 
   /** Exception thrown when a token does not parse correctly. */
-  public static class InvalidTokenException extends Exception {
+  class InvalidTokenException extends Exception {
     private static final long serialVersionUID = 1L;
 
     public InvalidTokenException() {
@@ -52,7 +52,7 @@
   }
 
   /** Pair returned from decode to provide the data used during encode. */
-  public static class ParsedToken {
+  class ParsedToken {
     private final Account.Id accountId;
     private final String emailAddress;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergeFailSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergeFailSender.java
index 3dfbcda..3883786 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergeFailSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergeFailSender.java
@@ -23,7 +23,7 @@
 
 /** Send notice about a change failing to merged. */
 public class MergeFailSender extends ReplyToChangeSender {
-  public static interface Factory {
+  public interface Factory {
     MergeFailSender create(Project.NameKey project, Change.Id id);
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergedSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergedSender.java
index 7271c18..f6c3d0f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergedSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergedSender.java
@@ -31,7 +31,7 @@
 
 /** Send notice about a change successfully merged. */
 public class MergedSender extends ReplyToChangeSender {
-  public static interface Factory {
+  public interface Factory {
     MergedSender create(Project.NameKey project, Change.Id id);
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/OutgoingEmail.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/OutgoingEmail.java
index 0442e23..aeb56d7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/OutgoingEmail.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/OutgoingEmail.java
@@ -303,7 +303,7 @@
     } else if (email != null) {
       return email;
 
-    } else /* (name == null && email == null) */{
+    } else /* (name == null && email == null) */ {
       return args.anonymousCowardName + " #" + accountId;
     }
   }
@@ -494,9 +494,11 @@
         j.remove();
       }
     }
-    for (EmailHeader hdr : headers.values()) {
-      if (hdr instanceof AddressList) {
-        ((AddressList) hdr).remove(fromEmail);
+    for (Map.Entry<String, EmailHeader> entry : headers.entrySet()) {
+      // Don't remove fromEmail from the "From" header though!
+      if (entry.getValue() instanceof AddressList
+          && !entry.getKey().equals("From")) {
+        ((AddressList) entry.getValue()).remove(fromEmail);
       }
     }
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplacePatchSetSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplacePatchSetSender.java
index 6bee3e8..df9f20e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplacePatchSetSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplacePatchSetSender.java
@@ -31,7 +31,7 @@
 
 /** Send notice of new patch sets for reviewers. */
 public class ReplacePatchSetSender extends ReplyToChangeSender {
-  public static interface Factory {
+  public interface Factory {
     ReplacePatchSetSender create(Project.NameKey project, Change.Id id);
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplyToChangeSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplyToChangeSender.java
index 8eadeef..dd922d3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplyToChangeSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplyToChangeSender.java
@@ -22,7 +22,7 @@
 
 /** Alert a user to a reply to a change, usually commentary made during review. */
 public abstract class ReplyToChangeSender extends ChangeEmail {
-  public static interface Factory<T extends ReplyToChangeSender> {
+  public interface Factory<T extends ReplyToChangeSender> {
     T create(Project.NameKey project, Change.Id id);
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/RestoredSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/RestoredSender.java
index 0808090..d946eb2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/RestoredSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/RestoredSender.java
@@ -24,7 +24,7 @@
 
 /** Send notice about a change being restored by its owner. */
 public class RestoredSender extends ReplyToChangeSender {
-  public static interface Factory extends
+  public interface Factory extends
       ReplyToChangeSender.Factory<RestoredSender> {
     @Override
     RestoredSender create(Project.NameKey project, Change.Id id);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/RevertedSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/RevertedSender.java
index 55438fe..2c9c37e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/RevertedSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/RevertedSender.java
@@ -24,7 +24,7 @@
 
 /** Send notice about a change being reverted. */
 public class RevertedSender extends ReplyToChangeSender {
-  public static interface Factory {
+  public interface Factory {
     RevertedSender create(Project.NameKey project, Change.Id id);
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/SmtpEmailSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/SmtpEmailSender.java
index aa57247..e263c6a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/SmtpEmailSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/SmtpEmailSender.java
@@ -57,7 +57,7 @@
     }
   }
 
-  public static enum Encryption {
+  public enum Encryption {
     NONE, SSL, TLS
   }
 
@@ -159,10 +159,10 @@
     setMissingHeader(hdrs, "Content-Transfer-Encoding", "8bit");
     setMissingHeader(hdrs, "Content-Disposition", "inline");
     setMissingHeader(hdrs, "User-Agent", "Gerrit/" + Version.getVersion());
-    if(importance != null) {
+    if (importance != null) {
       setMissingHeader(hdrs, "Importance", importance);
     }
-    if(expiryDays > 0) {
+    if (expiryDays > 0) {
       Date expiry = new Date(TimeUtil.nowMs() +
         expiryDays * 24 * 60 * 60 * 1000L );
       setMissingHeader(hdrs, "Expiry-Date",
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/AbstractChangeNotes.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/AbstractChangeNotes.java
index d3fbb58..b9747ac 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/AbstractChangeNotes.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/AbstractChangeNotes.java
@@ -75,7 +75,7 @@
   }
 
   @AutoValue
-  public static abstract class LoadHandle implements AutoCloseable {
+  public abstract static class LoadHandle implements AutoCloseable {
     public static LoadHandle create(RevWalk walk, ObjectId id) {
       return new AutoValue_AbstractChangeNotes_LoadHandle(
           checkNotNull(walk), id != null ? id.copy() : null);
@@ -125,8 +125,7 @@
       return self();
     }
     try (Timer1.Context timer = args.metrics.readLatency.start(CHANGES);
-        Repository repo =
-            args.repoManager.openMetadataRepository(getProjectName());
+        Repository repo = args.repoManager.openRepository(getProjectName());
         LoadHandle handle = openHandle(repo)) {
       revision = handle.id();
       onLoad(handle);
@@ -155,8 +154,7 @@
     } else if (!args.migration.enabled()) {
       return null;
     }
-    try (Repository repo =
-        args.repoManager.openMetadataRepository(getProjectName())) {
+    try (Repository repo = args.repoManager.openRepository(getProjectName())) {
       Ref ref = repo.getRefDatabase().exactRef(getRefName());
       return ref != null ? ref.getObjectId() : null;
     } catch (IOException e) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/AbstractChangeUpdate.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/AbstractChangeUpdate.java
index f2d3a09..b55b416 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/AbstractChangeUpdate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/AbstractChangeUpdate.java
@@ -15,6 +15,7 @@
 package com.google.gerrit.server.notedb;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
 
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.Change;
@@ -23,7 +24,6 @@
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.InternalUser;
-import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gwtorm.server.OrmException;
 
@@ -41,63 +41,69 @@
 /** A single delta related to a specific patch-set of a change. */
 public abstract class AbstractChangeUpdate {
   protected final NotesMigration migration;
-  protected final GitRepositoryManager repoManager;
-  protected final ChangeControl ctl;
-  protected final String anonymousCowardName;
   protected final ChangeNoteUtil noteUtil;
+  protected final String anonymousCowardName;
+  protected final ChangeNotes notes;
+  protected final Account.Id accountId;
+  protected final PersonIdent authorIdent;
   protected final Date when;
   private final PersonIdent serverIdent;
 
   protected PatchSet.Id psId;
   private ObjectId result;
 
-  protected AbstractChangeUpdate(NotesMigration migration,
-      GitRepositoryManager repoManager,
+  protected AbstractChangeUpdate(
+      NotesMigration migration,
       ChangeControl ctl,
       PersonIdent serverIdent,
       String anonymousCowardName,
       ChangeNoteUtil noteUtil,
       Date when) {
+    this(
+        migration,
+        noteUtil,
+        serverIdent,
+        anonymousCowardName,
+        ctl.getNotes(),
+        accountId(ctl.getUser()),
+        ident(noteUtil, serverIdent, anonymousCowardName, ctl.getUser(), when),
+        when);
+  }
+
+  protected AbstractChangeUpdate(
+      NotesMigration migration,
+      ChangeNoteUtil noteUtil,
+      PersonIdent serverIdent,
+      String anonymousCowardName,
+      ChangeNotes notes,
+      Account.Id accountId,
+      PersonIdent authorIdent,
+      Date when) {
     this.migration = migration;
-    this.repoManager = repoManager;
-    this.ctl = ctl;
-    this.serverIdent = serverIdent;
-    this.anonymousCowardName = anonymousCowardName;
     this.noteUtil = noteUtil;
+    this.serverIdent = new PersonIdent(serverIdent, when);
+    this.anonymousCowardName = anonymousCowardName;
+    this.notes = notes;
+    this.accountId = accountId;
+    this.authorIdent = authorIdent;
     this.when = when;
+  }
+
+  private static void checkUserType(CurrentUser user) {
     checkArgument(
-        (ctl.getUser() instanceof IdentifiedUser)
-            || (ctl.getUser() instanceof InternalUser),
-        "user must be IdentifiedUser or InternalUser: %s", ctl.getUser());
+        (user instanceof IdentifiedUser) || (user instanceof InternalUser),
+        "user must be IdentifiedUser or InternalUser: %s", user);
   }
 
-  public ChangeNotes getChangeNotes() {
-    return ctl.getNotes();
+  private static Account.Id accountId(CurrentUser u) {
+    checkUserType(u);
+    return (u instanceof IdentifiedUser) ? u.getAccountId() : null;
   }
 
-  public Change getChange() {
-    return ctl.getChange();
-  }
-
-  public Date getWhen() {
-    return when;
-  }
-
-  public CurrentUser getUser() {
-    return ctl.getUser();
-  }
-
-  public PatchSet.Id getPatchSetId() {
-    return psId;
-  }
-
-  public void setPatchSetId(PatchSet.Id psId) {
-    checkArgument(psId == null || psId.getParentKey().equals(ctl.getId()));
-    this.psId = psId;
-  }
-
-  private PersonIdent newAuthorIdent() {
-    CurrentUser u = getUser();
+  private static PersonIdent ident(ChangeNoteUtil noteUtil,
+      PersonIdent serverIdent, String anonymousCowardName, CurrentUser u,
+      Date when) {
+    checkUserType(u);
     if (u instanceof IdentifiedUser) {
       return noteUtil.newIdent(u.asIdentifiedUser().getAccount(), when,
           serverIdent, anonymousCowardName);
@@ -107,6 +113,42 @@
     throw new IllegalStateException();
   }
 
+  public Change.Id getId() {
+    return notes.getChangeId();
+  }
+
+  public ChangeNotes getNotes() {
+    return notes;
+  }
+
+  public Change getChange() {
+    return notes.getChange();
+  }
+
+  public Date getWhen() {
+    return when;
+  }
+
+  public PatchSet.Id getPatchSetId() {
+    return psId;
+  }
+
+  public void setPatchSetId(PatchSet.Id psId) {
+    checkArgument(psId == null || psId.getParentKey().equals(getId()));
+    this.psId = psId;
+  }
+
+  public Account.Id getAccountId() {
+    checkState(accountId != null,
+        "author identity for %s is not from an IdentifiedUser: %s",
+        getClass().getSimpleName(), authorIdent.toExternalString());
+    return accountId;
+  }
+
+  public Account.Id getNullableAccountId() {
+    return accountId;
+  }
+
   protected PersonIdent newIdent(Account author, Date when) {
     return noteUtil.newIdent(author, when, serverIdent, anonymousCowardName);
   }
@@ -144,8 +186,10 @@
     if (cb == null) {
       result = z;
       return z; // Impl intends to delete the ref.
+    } else if (cb == NO_OP_UPDATE) {
+      return null; // Impl is a no-op.
     }
-    cb.setAuthor(newAuthorIdent());
+    cb.setAuthor(authorIdent);
     cb.setCommitter(new PersonIdent(serverIdent, when));
     if (!curr.equals(z)) {
       cb.setParentId(curr);
@@ -172,13 +216,17 @@
    *     the meta ref should be deleted as a result of this update. The parent,
    *     author, and committer fields in the return value are always
    *     overwritten. The tree ID may be unset by this method, which indicates
-   *     to the caller that it should be copied from the parent commit.
+   *     to the caller that it should be copied from the parent commit. To
+   *     indicate that this update is a no-op (but this could not be determined
+   *     by {@link #isEmpty()}), return the sentinel {@link #NO_OP_UPDATE}.
    * @throws OrmException if a Gerrit-level error occurred.
    * @throws IOException if a lower-level error occurred.
    */
   protected abstract CommitBuilder applyImpl(RevWalk rw, ObjectInserter ins,
       ObjectId curr) throws OrmException, IOException;
 
+  protected static final CommitBuilder NO_OP_UPDATE = new CommitBuilder();
+
   ObjectId getResult() {
     return result;
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeBundle.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeBundle.java
index 51b80cd..459ba1f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeBundle.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeBundle.java
@@ -28,6 +28,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
 import com.google.common.collect.Ordering;
 import com.google.common.collect.Sets;
 import com.google.gerrit.reviewdb.client.Change;
@@ -222,13 +223,13 @@
         // the Change with the state implied by a ChangeNotes.
         101);
     checkColumns(ChangeMessage.Key.class, 1, 2);
-    checkColumns(ChangeMessage.class, 1, 2, 3, 4, 5);
+    checkColumns(ChangeMessage.class, 1, 2, 3, 4, 5, 6);
     checkColumns(PatchSet.Id.class, 1, 2);
     checkColumns(PatchSet.class, 1, 2, 3, 4, 5, 6, 8);
     checkColumns(PatchSetApproval.Key.class, 1, 2, 3);
-    checkColumns(PatchSetApproval.class, 1, 2, 3);
+    checkColumns(PatchSetApproval.class, 1, 2, 3, 6);
     checkColumns(PatchLineComment.Key.class, 1, 2);
-    checkColumns(PatchLineComment.class, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+    checkColumns(PatchLineComment.class, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
   }
 
   private final Change change;
@@ -332,8 +333,7 @@
       return;
     }
 
-    // At least one is from NoteDb, so we need to ignore UUIDs for both, and
-    // allow timestamp slop if the sources differ.
+    // At least one is from NoteDb, so comparisons are inexact as noted below.
     Change.Id id = bundleA.getChange().getId();
     checkArgument(id.equals(bundleB.getChange().getId()));
     List<ChangeMessage> as = bundleA.changeMessages;
@@ -349,8 +349,25 @@
       ChangeMessage a = as.get(i);
       ChangeMessage b = bs.get(i);
       String desc = "ChangeMessage on " + id + " at index " + i;
+
+      // Ignore null PatchSet.Id on a ReviewDb change; all entities in NoteDb
+      // have a PatchSet.Id.
+      boolean checkPsId = true;
+      if (bundleA.source == REVIEW_DB) {
+        checkPsId = a.getPatchSetId() != null;
+      } else if (bundleB.source == REVIEW_DB) {
+        checkPsId = b.getPatchSetId() != null;
+      }
+
+      // Ignore UUIDs for both sides.
+      List<String> exclude = Lists.newArrayList("key");
+      if (!checkPsId) {
+        exclude.add("patchset");
+      }
+
+      // Normal column-wise diff also allows timestamp slop.
       diffColumnsExcluding(diffs, ChangeMessage.class, desc, bundleA, a,
-          bundleB, b, "key");
+          bundleB, b, exclude);
     }
   }
 
@@ -417,7 +434,14 @@
   private static <T> void diffColumnsExcluding(List<String> diffs,
       Class<T> clazz, String desc, ChangeBundle bundleA, T a,
       ChangeBundle bundleB, T b, String... exclude) {
-    Set<String> toExclude = Sets.newLinkedHashSet(Arrays.asList(exclude));
+    diffColumnsExcluding(diffs, clazz, desc, bundleA, a, bundleB, b,
+        Arrays.asList(exclude));
+  }
+
+  private static <T> void diffColumnsExcluding(List<String> diffs,
+      Class<T> clazz, String desc, ChangeBundle bundleA, T a,
+      ChangeBundle bundleB, T b, Iterable<String> exclude) {
+    Set<String> toExclude = Sets.newLinkedHashSet(exclude);
     for (Field f : clazz.getDeclaredFields()) {
       Column col = f.getAnnotation(Column.class);
       if (col == null) {
@@ -447,7 +471,8 @@
     checkArgument(a.getClass() == b.getClass());
     Class<?> clazz = a.getClass();
 
-    Timestamp ta, tb;
+    Timestamp ta;
+    Timestamp tb;
     try {
       Field f = clazz.getDeclaredField(field);
       checkArgument(f.getAnnotation(Column.class) != null);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeDraftUpdate.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeDraftUpdate.java
index 1ab1d70..c3457ed 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeDraftUpdate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeDraftUpdate.java
@@ -16,8 +16,6 @@
 
 import static com.google.common.base.MoreObjects.firstNonNull;
 import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
 import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
 
 import com.google.auto.value.AutoValue;
@@ -28,11 +26,8 @@
 import com.google.gerrit.reviewdb.client.RefNames;
 import com.google.gerrit.reviewdb.client.RevId;
 import com.google.gerrit.server.GerritPersonIdent;
-import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.config.AllUsersName;
 import com.google.gerrit.server.config.AnonymousCowardName;
-import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.project.ChangeControl;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.assistedinject.Assisted;
 import com.google.inject.assistedinject.AssistedInject;
@@ -46,9 +41,11 @@
 import org.eclipse.jgit.revwalk.RevWalk;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Date;
-import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -63,11 +60,12 @@
  */
 public class ChangeDraftUpdate extends AbstractChangeUpdate {
   public interface Factory {
-    ChangeDraftUpdate create(ChangeControl ctl, Date when);
+    ChangeDraftUpdate create(ChangeNotes notes, Account.Id accountId,
+        PersonIdent authorIdent, Date when);
   }
 
   @AutoValue
-  static abstract class Key {
+  abstract static class Key {
     abstract RevId revId();
     abstract PatchLineComment.Key key();
   }
@@ -77,31 +75,25 @@
   }
 
   private final AllUsersName draftsProject;
-  private final Account.Id accountId;
 
-  // TODO: can go back to a list?
-  private Map<Key, PatchLineComment> put;
+  private List<PatchLineComment> put;
   private Set<Key> delete;
 
   @AssistedInject
   private ChangeDraftUpdate(
       @GerritPersonIdent PersonIdent serverIdent,
       @AnonymousCowardName String anonymousCowardName,
-      GitRepositoryManager repoManager,
       NotesMigration migration,
       AllUsersName allUsers,
       ChangeNoteUtil noteUtil,
-      @Assisted ChangeControl ctl,
+      @Assisted ChangeNotes notes,
+      @Assisted Account.Id accountId,
+      @Assisted PersonIdent authorIdent,
       @Assisted Date when) {
-    super(migration, repoManager, ctl, serverIdent, anonymousCowardName,
-        noteUtil, when);
+    super(migration, noteUtil, serverIdent, anonymousCowardName, notes,
+        accountId, authorIdent, when);
     this.draftsProject = allUsers;
-    checkState(ctl.getUser().isIdentifiedUser(),
-        "Current user must be identified");
-    IdentifiedUser user = ctl.getUser().asIdentifiedUser();
-    this.accountId = user.getAccountId();
-
-    this.put = new HashMap<>();
+    this.put = new ArrayList<>();
     this.delete = new HashSet<>();
   }
 
@@ -109,7 +101,7 @@
     verifyComment(c);
     checkArgument(c.getStatus() == PatchLineComment.Status.DRAFT,
         "Cannot insert a published comment into a ChangeDraftUpdate");
-    put.put(key(c), c);
+    put.add(c);
   }
 
   public void deleteComment(PatchLineComment c) {
@@ -127,15 +119,15 @@
         + " this ChangeDraftUpdate (%s): %s", accountId, comment);
   }
 
-  /** @return the tree id for the updated tree */
-  private ObjectId storeCommentsInNotes(RevWalk rw, ObjectInserter ins,
-      ObjectId curr) throws ConfigInvalidException, OrmException, IOException {
+  private CommitBuilder storeCommentsInNotes(RevWalk rw, ObjectInserter ins,
+      ObjectId curr, CommitBuilder cb)
+      throws ConfigInvalidException, OrmException, IOException {
     RevisionNoteMap rnm = getRevisionNoteMap(rw, curr);
     Set<RevId> updatedRevs =
         Sets.newHashSetWithExpectedSize(rnm.revisionNotes.size());
     RevisionNoteBuilder.Cache cache = new RevisionNoteBuilder.Cache(rnm);
 
-    for (PatchLineComment c : put.values()) {
+    for (PatchLineComment c : put) {
       if (!delete.contains(key(c))) {
         cache.get(c.getRevId()).putComment(c);
       }
@@ -145,11 +137,15 @@
     }
 
     Map<RevId, RevisionNoteBuilder> builders = cache.getBuilders();
+    boolean touchedAnyRevs = false;
     boolean hasComments = false;
     for (Map.Entry<RevId, RevisionNoteBuilder> e : builders.entrySet()) {
       updatedRevs.add(e.getKey());
       ObjectId id = ObjectId.fromString(e.getKey().get());
       byte[] data = e.getValue().build(noteUtil);
+      if (!Arrays.equals(data, e.getValue().baseRaw)) {
+        touchedAnyRevs = true;
+      }
       if (data.length == 0) {
         rnm.noteMap.remove(id);
       } else {
@@ -159,6 +155,13 @@
       }
     }
 
+    // If we didn't touch any notes, tell the caller this was a no-op update. We
+    // couldn't have done this in isEmpty() below because we hadn't read the old
+    // data yet.
+    if (!touchedAnyRevs) {
+      return NO_OP_UPDATE;
+    }
+
     // If we touched every revision and there are no comments left, tell the
     // caller to delete the entire ref.
     boolean touchedAllRevs = updatedRevs.equals(rnm.revisionNotes.keySet());
@@ -166,7 +169,8 @@
       return null;
     }
 
-    return rnm.noteMap.writeTree(ins);
+    cb.setTreeId(rnm.noteMap.writeTree(ins));
+    return cb;
   }
 
   private RevisionNoteMap getRevisionNoteMap(RevWalk rw, ObjectId curr)
@@ -176,12 +180,13 @@
       // already parsed the revision notes. We can reuse them as long as the ref
       // hasn't advanced.
       DraftCommentNotes draftNotes =
-          ctl.getNotes().load().getDraftCommentNotes();
+          getNotes().load().getDraftCommentNotes();
       if (draftNotes != null) {
         ObjectId idFromNotes =
             firstNonNull(draftNotes.getRevision(), ObjectId.zeroId());
-        if (idFromNotes.equals(curr)) {
-          return checkNotNull(ctl.getNotes().revisionNoteMap);
+        RevisionNoteMap rnm = draftNotes.getRevisionNoteMap();
+        if (idFromNotes.equals(curr) && rnm != null) {
+          return rnm;
         }
       }
     }
@@ -194,7 +199,7 @@
     // Even though reading from changes might not be enabled, we need to
     // parse any existing revision notes so we can merge them.
     return RevisionNoteMap.parse(
-        noteUtil, ctl.getId(), rw.getObjectReader(), noteMap, true);
+        noteUtil, getId(), rw.getObjectReader(), noteMap, true);
   }
 
   @Override
@@ -203,15 +208,10 @@
     CommitBuilder cb = new CommitBuilder();
     cb.setMessage("Update draft comments");
     try {
-      ObjectId treeId = storeCommentsInNotes(rw, ins, curr);
-      if (treeId == null) {
-        return null; // Delete ref.
-      }
-      cb.setTreeId(checkNotNull(treeId));
+      return storeCommentsInNotes(rw, ins, curr, cb);
     } catch (ConfigInvalidException e) {
       throw new OrmException(e);
     }
-    return cb;
   }
 
   @Override
@@ -221,7 +221,7 @@
 
   @Override
   protected String getRefName() {
-    return RefNames.refsDraftComments(accountId, ctl.getId());
+    return RefNames.refsDraftComments(accountId, getId());
   }
 
   @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNoteUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNoteUtil.java
index 40bbb29..14e40ab 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNoteUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNoteUtil.java
@@ -55,8 +55,10 @@
 import java.sql.Timestamp;
 import java.text.ParseException;
 import java.util.Date;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
+import java.util.Set;
 
 public class ChangeNoteUtil {
   static final FooterKey FOOTER_BRANCH = new FooterKey("Branch");
@@ -72,6 +74,7 @@
   static final FooterKey FOOTER_SUBMITTED_WITH =
       new FooterKey("Submitted-with");
   static final FooterKey FOOTER_TOPIC = new FooterKey("Topic");
+  static final FooterKey FOOTER_TAG = new FooterKey("Tag");
 
   private static final String AUTHOR = "Author";
   private static final String BASE_PATCH_SET = "Base-for-patch-set";
@@ -82,6 +85,7 @@
   private static final String PATCH_SET = "Patch-set";
   private static final String REVISION = "Revision";
   private static final String UUID = "UUID";
+  private static final String TAG = FOOTER_TAG.getName();
 
   public static String changeRefName(Change.Id id) {
     StringBuilder r = new StringBuilder();
@@ -152,6 +156,7 @@
     if (p.value >= note.length) {
       return ImmutableList.of();
     }
+    Set<PatchLineComment.Key> seen = new HashSet<>();
     List<PatchLineComment> result = Lists.newArrayList();
     int sizeOfNote = note.length;
 
@@ -169,6 +174,10 @@
           null : c.getKey().getParentKey().getFileName();
       c = parseComment(note, p, previousFileName, psId, revId,
           isForBase, status);
+      if (!seen.add(c.getKey())) {
+        throw parseException(
+            changeId, "multiple comments for %s in note", c.getKey());
+      }
       result.add(c);
     }
     return result;
@@ -205,6 +214,14 @@
     }
 
     String uuid = parseStringField(note, curr, changeId, UUID);
+
+    boolean hasTag =
+        (RawParseUtils.match(note, curr.value, TAG.getBytes(UTF_8))) != -1;
+    String tag = null;
+    if (hasTag) {
+      tag = parseStringField(note, curr, changeId, TAG);
+    }
+
     int commentLength = parseCommentLength(note, curr, changeId);
 
     String message = RawParseUtils.decode(
@@ -215,6 +232,7 @@
         new PatchLineComment.Key(new Patch.Key(psId, currentFileName), uuid),
         range.getEndLine(), aId, parentUUID, commentTime);
     plc.setMessage(message);
+    plc.setTag(tag);
     plc.setSide((short) (isForBase ? 0 : 1));
     if (range.getStartCharacter() != -1) {
       plc.setRange(range);
@@ -362,7 +380,7 @@
     int commentLength =
         RawParseUtils.parseBase10(note, startOfLength, i);
     int endOfLine = RawParseUtils.nextLF(note, curr.value);
-    if (i.value != endOfLine-1) {
+    if (i.value != endOfLine - 1) {
       throw parseException(changeId, "could not parse %s", PATCH_SET);
     }
     curr.value = endOfLine;
@@ -494,6 +512,10 @@
 
         appendHeaderField(writer, UUID, c.getKey().get());
 
+        if (c.getTag() != null) {
+          appendHeaderField(writer, TAG, c.getTag());
+        }
+
         byte[] messageBytes = c.getMessage().getBytes(UTF_8);
         appendHeaderField(writer, LENGTH,
             Integer.toString(messageBytes.length));
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotes.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotes.java
index a6bf5d3..1f439f6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotes.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotes.java
@@ -491,7 +491,8 @@
       throws OrmException {
     if (draftCommentNotes == null ||
         !author.equals(draftCommentNotes.getAuthor())) {
-      draftCommentNotes = new DraftCommentNotes(args, change, author);
+      draftCommentNotes =
+          new DraftCommentNotes(args, change, author, autoRebuild);
       draftCommentNotes.load();
     }
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotesParser.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotesParser.java
index 7bf7960..69209b9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotesParser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeNotesParser.java
@@ -25,6 +25,7 @@
 import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_SUBJECT;
 import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_SUBMISSION_ID;
 import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_SUBMITTED_WITH;
+import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_TAG;
 import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_TOPIC;
 import static com.google.gerrit.server.notedb.NoteDbTable.CHANGES;
 
@@ -85,6 +86,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.NavigableSet;
 import java.util.Set;
 import java.util.TreeMap;
@@ -113,6 +115,7 @@
   String subject;
   String originalSubject;
   String submissionId;
+  String tag;
   PatchSet.Id currentPatchSetId;
   RevisionNoteMap revisionNoteMap;
 
@@ -123,7 +126,7 @@
   private final RevWalk walk;
   private final Repository repo;
   private final Map<PatchSet.Id,
-      Table<Account.Id, String, Optional<PatchSetApproval>>> approvals;
+      Table<Account.Id, Entry<String, String>, Optional<PatchSetApproval>>> approvals;
   private final List<ChangeMessage> allChangeMessages;
   private final Multimap<PatchSet.Id, ChangeMessage> changeMessagesByPatchSet;
 
@@ -134,7 +137,7 @@
     this.id = changeId;
     this.tip = tip;
     this.walk = walk;
-    this.repo = repoManager.openMetadataRepository(project);
+    this.repo = repoManager.openRepository(project);
     this.noteUtil = noteUtil;
     this.metrics = metrics;
     approvals = Maps.newHashMap();
@@ -206,6 +209,9 @@
 
     boolean updateTs = commit.getParentCount() == 0;
     createdOn = ts;
+    parseTag(commit);
+    updateTs |= tag != null;
+
     if (branch == null) {
       branch = parseBranch(commit);
       updateTs |= branch != null;
@@ -405,6 +411,18 @@
     }
   }
 
+  private void parseTag(RevCommit commit) throws ConfigInvalidException {
+    tag = null;
+    List<String> tagLines = commit.getFooterLines(FOOTER_TAG);
+    if (tagLines.isEmpty()) {
+      return;
+    } else if (tagLines.size() == 1) {
+      tag = tagLines.get(0);
+    } else {
+      throw expectedOneFooter(FOOTER_TAG, tagLines);
+    }
+  }
+
   private Change.Status parseStatus(RevCommit commit)
       throws ConfigInvalidException {
     List<String> statusLines = commit.getFooterLines(FOOTER_STATUS);
@@ -479,7 +497,7 @@
 
     int ptr = size - 1;
     int changeMessageEnd = -1;
-    while(ptr > changeMessageStart) {
+    while (ptr > changeMessageStart) {
       ptr = RawParseUtils.prevLF(raw, ptr, '\r');
       if (ptr == -1) {
         break;
@@ -505,6 +523,7 @@
         ts,
         psId);
     changeMessage.setMessage(changeMsgString);
+    changeMessage.setTag(tag);
     changeMessagesByPatchSet.put(psId, changeMessage);
     allChangeMessages.add(changeMessage);
     return changeMessage;
@@ -570,36 +589,39 @@
       throw pe;
     }
 
-    Table<Account.Id, String, Optional<PatchSetApproval>> curr =
-        getApprovalsTableIfNoVotePresent(psId, accountId, l.label());
+    Entry<String, String> label = Maps.immutableEntry(l.label(), tag);
+    Table<Account.Id, Entry<String, String>, Optional<PatchSetApproval>> curr =
+        getApprovalsTableIfNoVotePresent(psId, accountId, label);
     if (curr != null) {
-      curr.put(accountId, l.label(), Optional.of(new PatchSetApproval(
+      PatchSetApproval psa = new PatchSetApproval(
           new PatchSetApproval.Key(
               psId,
               accountId,
               new LabelId(l.label())),
           l.value(),
-          ts)));
+          ts);
+      psa.setTag(tag);
+      curr.put(accountId, label, Optional.of(psa));
     }
   }
 
   private void parseRemoveApproval(PatchSet.Id psId, Account.Id committerId,
       String line) throws ConfigInvalidException {
     Account.Id accountId;
-    String label;
+    Entry<String, String> label;
     int s = line.indexOf(' ');
     if (s > 0) {
-      label = line.substring(1, s);
+      label = Maps.immutableEntry(line.substring(1, s), tag);
       PersonIdent ident = RawParseUtils.parsePersonIdent(line.substring(s + 1));
       checkFooter(ident != null, FOOTER_LABEL, line);
       accountId = noteUtil.parseIdent(ident, id);
     } else {
-      label = line.substring(1);
+      label = Maps.immutableEntry(line.substring(1), tag);
       accountId = committerId;
     }
 
     try {
-      LabelType.checkNameInternal(label);
+      LabelType.checkNameInternal(label.getKey());
     } catch (IllegalArgumentException e) {
       ConfigInvalidException pe =
           parseException("invalid %s: %s", FOOTER_LABEL, line);
@@ -607,18 +629,18 @@
       throw pe;
     }
 
-    Table<Account.Id, String, Optional<PatchSetApproval>> curr =
+    Table<Account.Id, Entry<String, String>, Optional<PatchSetApproval>> curr =
         getApprovalsTableIfNoVotePresent(psId, accountId, label);
     if (curr != null) {
       curr.put(accountId, label, Optional.<PatchSetApproval> absent());
     }
   }
 
-  private Table<Account.Id, String, Optional<PatchSetApproval>>
+  private Table<Account.Id, Entry<String, String>, Optional<PatchSetApproval>>
       getApprovalsTableIfNoVotePresent(PatchSet.Id psId, Account.Id accountId,
-        String label) {
+        Entry<String, String> label) {
 
-    Table<Account.Id, String, Optional<PatchSetApproval>> curr =
+    Table<Account.Id, Entry<String, String>, Optional<PatchSetApproval>> curr =
         approvals.get(psId);
     if (curr != null) {
       if (curr.contains(accountId, label)) {
@@ -626,11 +648,11 @@
       }
     } else {
       curr = Tables.newCustomTable(
-          Maps.<Account.Id, Map<String, Optional<PatchSetApproval>>>
+          Maps.<Account.Id, Map<Entry<String, String>, Optional<PatchSetApproval>>>
               newHashMapWithExpectedSize(2),
-          new Supplier<Map<String, Optional<PatchSetApproval>>>() {
+          new Supplier<Map<Entry<String, String>, Optional<PatchSetApproval>>>() {
             @Override
-            public Map<String, Optional<PatchSetApproval>> get() {
+            public Map<Entry<String, String>, Optional<PatchSetApproval>> get() {
               return Maps.newLinkedHashMap();
             }
           });
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeRebuilderImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeRebuilderImpl.java
index df4d381..c9a14e9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeRebuilderImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeRebuilderImpl.java
@@ -15,6 +15,7 @@
 package com.google.gerrit.server.notedb;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.gerrit.server.PatchLineCommentsUtil.setCommentRevId;
 import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_HASHTAGS;
@@ -22,15 +23,18 @@
 import static java.util.concurrent.TimeUnit.SECONDS;
 
 import com.google.common.base.MoreObjects;
+import com.google.common.base.Predicate;
 import com.google.common.base.Splitter;
 import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.ComparisonChain;
+import com.google.common.collect.FluentIterable;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Multimap;
 import com.google.common.collect.Ordering;
 import com.google.common.collect.Sets;
 import com.google.common.primitives.Ints;
+import com.google.gerrit.common.Nullable;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.ChangeMessage;
@@ -39,24 +43,25 @@
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.client.PatchSetApproval;
 import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gerrit.server.CurrentUser;
-import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.InternalUser;
+import com.google.gerrit.reviewdb.server.ReviewDbUtil;
+import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.PatchLineCommentsUtil;
+import com.google.gerrit.server.account.AccountCache;
+import com.google.gerrit.server.config.AnonymousCowardName;
 import com.google.gerrit.server.git.ChainedReceiveCommands;
 import com.google.gerrit.server.patch.PatchListCache;
-import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.NoSuchChangeException;
+import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.schema.DisabledChangesReviewDbWrapper;
 import com.google.gwtorm.server.OrmException;
 import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
-import com.google.inject.util.Providers;
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.errors.InvalidObjectIdException;
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.PersonIdent;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevWalk;
@@ -66,6 +71,7 @@
 import java.sql.Timestamp;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
@@ -90,37 +96,40 @@
    */
   private static final long MAX_DELTA_MS = SECONDS.toMillis(1);
 
-  private final ChangeControl.GenericFactory controlFactory;
-  private final IdentifiedUser.GenericFactory userFactory;
-  private final InternalUser.Factory internalUserFactory;
-  private final PatchListCache patchListCache;
-  private final ChangeNotes.Factory notesFactory;
-  private final ChangeUpdate.Factory updateFactory;
+  private final AccountCache accountCache;
   private final ChangeDraftUpdate.Factory draftUpdateFactory;
-  private final NoteDbUpdateManager.Factory updateManagerFactory;
+  private final ChangeNotes.Factory notesFactory;
   private final ChangeNoteUtil changeNoteUtil;
+  private final ChangeUpdate.Factory updateFactory;
+  private final NoteDbUpdateManager.Factory updateManagerFactory;
+  private final PatchListCache patchListCache;
+  private final PersonIdent serverIdent;
+  private final ProjectCache projectCache;
+  private final String anonymousCowardName;
 
   @Inject
   ChangeRebuilderImpl(SchemaFactory<ReviewDb> schemaFactory,
-      ChangeControl.GenericFactory controlFactory,
-      IdentifiedUser.GenericFactory userFactory,
-      InternalUser.Factory internalUserFactory,
-      PatchListCache patchListCache,
-      ChangeNotes.Factory notesFactory,
-      ChangeUpdate.Factory updateFactory,
+      AccountCache accountCache,
       ChangeDraftUpdate.Factory draftUpdateFactory,
+      ChangeNotes.Factory notesFactory,
+      ChangeNoteUtil changeNoteUtil,
+      ChangeUpdate.Factory updateFactory,
       NoteDbUpdateManager.Factory updateManagerFactory,
-      ChangeNoteUtil changeNoteUtil) {
+      PatchListCache patchListCache,
+      @GerritPersonIdent PersonIdent serverIdent,
+      @Nullable ProjectCache projectCache,
+      @AnonymousCowardName String anonymousCowardName) {
     super(schemaFactory);
-    this.controlFactory = controlFactory;
-    this.userFactory = userFactory;
-    this.internalUserFactory = internalUserFactory;
-    this.patchListCache = patchListCache;
-    this.notesFactory = notesFactory;
-    this.updateFactory = updateFactory;
+    this.accountCache = accountCache;
     this.draftUpdateFactory = draftUpdateFactory;
-    this.updateManagerFactory = updateManagerFactory;
+    this.notesFactory = notesFactory;
     this.changeNoteUtil = changeNoteUtil;
+    this.updateFactory = updateFactory;
+    this.updateManagerFactory = updateManagerFactory;
+    this.patchListCache = patchListCache;
+    this.serverIdent = serverIdent;
+    this.projectCache = projectCache;
+    this.anonymousCowardName = anonymousCowardName;
   }
 
   @Override
@@ -165,15 +174,12 @@
       OrmException, ConfigInvalidException {
     Change change = new Change(bundle.getChange());
     buildUpdates(manager, bundle);
-    NoteDbChangeState newState = NoteDbChangeState.applyDelta(
+    return NoteDbChangeState.applyDelta(
         change, manager.stage().get(change.getId()));
-    manager.execute();
-    return newState;
   }
 
   private void buildUpdates(NoteDbUpdateManager manager, ChangeBundle bundle)
-      throws NoSuchChangeException, IOException, OrmException,
-      ConfigInvalidException {
+      throws IOException, OrmException, ConfigInvalidException {
     Change change = new Change(bundle.getChange());
     // We will rebuild all events, except for draft comments, in buckets based
     // on author and timestamp.
@@ -188,11 +194,8 @@
     deleteRef(change, changeMetaRepo, manager.getChangeRepo().cmds);
 
     for (PatchSet ps : bundle.getPatchSets()) {
-      events.add(new PatchSetEvent(change, ps, manager.getCodeRepo().rw));
-      List<PatchLineComment> comments =
-          PatchLineCommentsUtil.PLC_ORDER.sortedCopy(
-              bundle.getPatchLineComments());
-      for (PatchLineComment c : comments) {
+      events.add(new PatchSetEvent(change, ps, manager.getChangeRepo().rw));
+      for (PatchLineComment c : getPatchLineComments(bundle, ps)) {
         PatchLineCommentEvent e =
             new PatchLineCommentEvent(c, change, ps, patchListCache);
         if (c.getStatus() == Status.PUBLISHED) {
@@ -213,7 +216,7 @@
           new ChangeMessageEvent(msg, noteDbChange, change.getCreatedOn()));
     }
 
-    Collections.sort(events, EVENT_ORDER);
+    sortEvents(change.getId(), events);
 
     events.add(new FinalUpdatesEvent(change, noteDbChange));
 
@@ -240,17 +243,53 @@
     }
   }
 
+  private static List<PatchLineComment> getPatchLineComments(ChangeBundle bundle,
+      final PatchSet ps) {
+    return FluentIterable.from(bundle.getPatchLineComments())
+        .filter(new Predicate<PatchLineComment>() {
+          @Override
+          public boolean apply(PatchLineComment in) {
+            return in.getPatchSetId().equals(ps.getId());
+          }
+        }).toSortedList(PatchLineCommentsUtil.PLC_ORDER);
+  }
+
+  private void sortEvents(Change.Id changeId, List<Event> events) {
+    Collections.sort(events, EVENT_ORDER);
+
+    // Fill in any missing patch set IDs using the latest patch set of the
+    // change at the time of the event. This is as if a user added a
+    // ChangeMessage on the change by replying from the latest patch set.
+    int ps = 1;
+    for (Event e : events) {
+      if (e.psId == null) {
+        e.psId = new PatchSet.Id(changeId, ps);
+      } else {
+        ps = Math.max(ps, e.psId.get());
+      }
+    }
+  }
+
   private void flushEventsToUpdate(NoteDbUpdateManager manager,
-      EventList<Event> events, Change change)
-      throws NoSuchChangeException, OrmException, IOException {
+      EventList<Event> events, Change change) throws OrmException, IOException {
     if (events.isEmpty()) {
       return;
     }
+    Comparator<String> labelNameComparator;
+    if (projectCache != null) {
+      labelNameComparator = projectCache.get(change.getProject())
+          .getLabelTypes().nameComparator();
+    } else {
+      // No project cache available, bail and use natural ordering; there's no
+      // semantic difference anyway difference.
+      labelNameComparator = Ordering.natural();
+    }
     ChangeUpdate update = updateFactory.create(
-        controlFactory.controlFor(
-            notesFactory.createWithAutoRebuildingDisabled(change),
-            events.getUser()),
-        events.getWhen());
+        notesFactory.createWithAutoRebuildingDisabled(change),
+        events.getAccountId(),
+        events.newAuthorIdent(),
+        events.getWhen(),
+        labelNameComparator);
     update.setAllowWriteToNewRef(true);
     update.setPatchSetId(events.getPatchSetId());
     for (Event e : events) {
@@ -262,14 +301,14 @@
 
   private void flushEventsToDraftUpdate(NoteDbUpdateManager manager,
       EventList<PatchLineCommentEvent> events, Change change)
-      throws NoSuchChangeException, OrmException {
+      throws OrmException {
     if (events.isEmpty()) {
       return;
     }
     ChangeDraftUpdate update = draftUpdateFactory.create(
-        controlFactory.controlFor(
-            notesFactory.createWithAutoRebuildingDisabled(change),
-            events.getUser()),
+        notesFactory.createWithAutoRebuildingDisabled(change),
+        events.getAccountId(),
+        events.newAuthorIdent(),
         events.getWhen());
     update.setPatchSetId(events.getPatchSetId());
     for (PatchLineCommentEvent e : events) {
@@ -348,8 +387,8 @@
       return ComparisonChain.start()
           .compareTrueFirst(a.predatesChange, b.predatesChange)
           .compare(a.when, b.when)
-          .compare(a.who.get(), b.who.get())
-          .compare(a.psId.get(), b.psId.get())
+          .compare(a.who, b.who, ReviewDbUtil.intKeyOrdering())
+          .compare(a.psId, b.psId, ReviewDbUtil.intKeyOrdering().nullsLast())
           .result();
     }
   };
@@ -358,10 +397,10 @@
     // NOTE: EventList only supports direct subclasses, not an arbitrary
     // hierarchy.
 
-    final PatchSet.Id psId;
     final Account.Id who;
     final Timestamp when;
     final boolean predatesChange;
+    PatchSet.Id psId;
 
     protected Event(PatchSet.Id psId, Account.Id who, Timestamp when,
         Timestamp changeCreatedOn) {
@@ -379,9 +418,9 @@
       checkState(when.getTime() - update.getWhen().getTime() <= MAX_WINDOW_MS,
           "event at %s outside update window starting at %s",
           when, update.getWhen());
-      checkState(Objects.equals(update.getUser().getAccountId(), who),
+      checkState(Objects.equals(update.getNullableAccountId(), who),
           "cannot apply event by %s to update by %s",
-          who, update.getUser().getAccountId());
+          who, update.getNullableAccountId());
     }
 
     /**
@@ -427,7 +466,7 @@
 
       Event last = getLast();
       if (!Objects.equals(e.who, last.who)
-          || !Objects.equals(e.psId, last.psId)) {
+          || !e.psId.equals(last.psId)) {
         return false; // Different patch set or author.
       }
 
@@ -460,26 +499,31 @@
     }
 
     PatchSet.Id getPatchSetId() {
-      PatchSet.Id id = get(0).psId;
+      PatchSet.Id id = checkNotNull(get(0).psId);
       for (int i = 1; i < size(); i++) {
-        checkState(Objects.equals(id, get(i).psId),
+        checkState(get(i).psId.equals(id),
             "mismatched patch sets in EventList: %s != %s", id, get(i).psId);
       }
       return id;
     }
 
-    CurrentUser getUser() {
+    Account.Id getAccountId() {
       Account.Id id = get(0).who;
       for (int i = 1; i < size(); i++) {
         checkState(Objects.equals(id, get(i).who),
             "mismatched users in EventList: %s != %s", id, get(i).who);
       }
+      return id;
+    }
+
+    PersonIdent newAuthorIdent() {
+      Account.Id id = getAccountId();
       if (id == null) {
-        return internalUserFactory.create();
+        return new PersonIdent(serverIdent, getWhen());
       }
-      // db is only used by IdentifiedUser to look up project watches, which are
-      // not needed for rebuilding changes.
-      return userFactory.create(Providers.of((ReviewDb) null), id);
+      return changeNoteUtil.newIdent(
+          accountCache.get(id).getAccount(), getWhen(), serverIdent,
+          anonymousCowardName);
     }
   }
 
@@ -534,7 +578,10 @@
         update.setSubjectForCommit("Create patch set " + ps.getPatchSetId());
       }
       setRevision(update, ps);
-      update.setGroups(ps.getGroups());
+      List<String> groups = ps.getGroups();
+      if (!groups.isEmpty()) {
+        update.setGroups(ps.getGroups());
+      }
       if (ps.isDraft()) {
         update.setPatchSetState(PatchSetState.DRAFT);
       }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeUpdate.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeUpdate.java
index 1388ee8..a947cb4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeUpdate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ChangeUpdate.java
@@ -29,30 +29,28 @@
 import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_SUBJECT;
 import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_SUBMISSION_ID;
 import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_SUBMITTED_WITH;
+import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_TAG;
 import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_TOPIC;
 import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
 
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Function;
 import com.google.common.base.Joiner;
 import com.google.common.base.Optional;
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Ordering;
 import com.google.common.collect.Table;
 import com.google.common.collect.TreeBasedTable;
+import com.google.gerrit.common.Nullable;
 import com.google.gerrit.common.data.SubmitRecord;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.PatchLineComment;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.client.RevId;
+import com.google.gerrit.reviewdb.server.ReviewDbUtil;
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.config.AnonymousCowardName;
-import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.util.LabelVote;
@@ -71,9 +69,11 @@
 import org.eclipse.jgit.revwalk.RevWalk;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.Date;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -94,6 +94,10 @@
   public interface Factory {
     ChangeUpdate create(ChangeControl ctl);
     ChangeUpdate create(ChangeControl ctl, Date when);
+    ChangeUpdate create(ChangeNotes notes, @Nullable Account.Id accountId,
+        PersonIdent authorIdent, Date when,
+        Comparator<String> labelNameComparator);
+
     @VisibleForTesting
     ChangeUpdate create(ChangeControl ctl, Date when,
         Comparator<String> labelNameComparator);
@@ -104,7 +108,8 @@
   private final NoteDbUpdateManager.Factory updateManagerFactory;
 
   private final Table<String, Account.Id, Optional<Short>> approvals;
-  private final Map<Account.Id, ReviewerStateInternal> reviewers;
+  private final Map<Account.Id, ReviewerStateInternal> reviewers = new LinkedHashMap<>();
+  private final List<PatchLineComment> comments = new ArrayList<>();
 
   private String commitSubject;
   private String subject;
@@ -113,11 +118,11 @@
   private Change.Status status;
   private List<SubmitRecord> submitRecords;
   private String submissionId;
-  private List<PatchLineComment> comments;
   private String topic;
   private String commit;
   private Set<String> hashtags;
   private String changeMessage;
+  private String tag;
   private PatchSetState psState;
   private Iterable<String> groups;
   private String pushCert;
@@ -129,7 +134,6 @@
   private ChangeUpdate(
       @GerritPersonIdent PersonIdent serverIdent,
       @AnonymousCowardName String anonymousCowardName,
-      GitRepositoryManager repoManager,
       NotesMigration migration,
       AccountCache accountCache,
       NoteDbUpdateManager.Factory updateManagerFactory,
@@ -137,7 +141,7 @@
       ProjectCache projectCache,
       @Assisted ChangeControl ctl,
       ChangeNoteUtil noteUtil) {
-    this(serverIdent, anonymousCowardName, repoManager, migration, accountCache,
+    this(serverIdent, anonymousCowardName, migration, accountCache,
         updateManagerFactory, draftUpdateFactory,
         projectCache, ctl, serverIdent.getWhen(), noteUtil);
   }
@@ -146,7 +150,6 @@
   private ChangeUpdate(
       @GerritPersonIdent PersonIdent serverIdent,
       @AnonymousCowardName String anonymousCowardName,
-      GitRepositoryManager repoManager,
       NotesMigration migration,
       AccountCache accountCache,
       NoteDbUpdateManager.Factory updateManagerFactory,
@@ -155,7 +158,7 @@
       @Assisted ChangeControl ctl,
       @Assisted Date when,
       ChangeNoteUtil noteUtil) {
-    this(serverIdent, anonymousCowardName, repoManager, migration, accountCache,
+    this(serverIdent, anonymousCowardName, migration, accountCache,
         updateManagerFactory, draftUpdateFactory, ctl,
         when,
         projectCache.get(getProjectName(ctl)).getLabelTypes().nameComparator(),
@@ -166,11 +169,15 @@
     return ctl.getProject().getNameKey();
   }
 
+  private static Table<String, Account.Id, Optional<Short>> approvals(
+      Comparator<String> nameComparator) {
+    return TreeBasedTable.create(nameComparator, ReviewDbUtil.intKeyOrdering());
+  }
+
   @AssistedInject
   private ChangeUpdate(
       @GerritPersonIdent PersonIdent serverIdent,
       @AnonymousCowardName String anonymousCowardName,
-      GitRepositoryManager repoManager,
       NotesMigration migration,
       AccountCache accountCache,
       NoteDbUpdateManager.Factory updateManagerFactory,
@@ -179,22 +186,34 @@
       @Assisted Date when,
       @Assisted Comparator<String> labelNameComparator,
       ChangeNoteUtil noteUtil) {
-    super(migration, repoManager, ctl, serverIdent,
+    super(migration, ctl, serverIdent,
         anonymousCowardName, noteUtil, when);
     this.accountCache = accountCache;
     this.draftUpdateFactory = draftUpdateFactory;
     this.updateManagerFactory = updateManagerFactory;
+    this.approvals = approvals(labelNameComparator);
+  }
 
-    this.approvals = TreeBasedTable.create(
-        labelNameComparator,
-        Ordering.natural().onResultOf(new Function<Account.Id, Integer>() {
-          @Override
-          public Integer apply(Account.Id in) {
-            return in.get();
-          }
-        }));
-    this.reviewers = Maps.newLinkedHashMap();
-    this.comments = Lists.newArrayList();
+  @AssistedInject
+  private ChangeUpdate(
+      @GerritPersonIdent PersonIdent serverIdent,
+      @AnonymousCowardName String anonymousCowardName,
+      NotesMigration migration,
+      AccountCache accountCache,
+      NoteDbUpdateManager.Factory updateManagerFactory,
+      ChangeDraftUpdate.Factory draftUpdateFactory,
+      ChangeNoteUtil noteUtil,
+      @Assisted ChangeNotes notes,
+      @Assisted @Nullable Account.Id accountId,
+      @Assisted PersonIdent authorIdent,
+      @Assisted Date when,
+      @Assisted Comparator<String> labelNameComparator) {
+    super(migration, noteUtil, serverIdent, anonymousCowardName, notes,
+        accountId, authorIdent, when);
+    this.accountCache = accountCache;
+    this.draftUpdateFactory = draftUpdateFactory;
+    this.updateManagerFactory = updateManagerFactory;
+    this.approvals = approvals(labelNameComparator);
   }
 
   public ObjectId commit() throws IOException, OrmException {
@@ -203,13 +222,13 @@
     updateManager.add(this);
     NoteDbChangeState.applyDelta(
         getChange(),
-        updateManager.stage().get(ctl.getId()));
+        updateManager.stage().get(getId()));
     updateManager.execute();
     return getResult();
   }
 
   public void setChangeId(String changeId) {
-    String old = ctl.getChange().getKey().get();
+    String old = getChange().getKey().get();
     checkArgument(old.equals(changeId),
         "The Change-Id was already set to %s, so we cannot set this Change-Id: %s",
         old, changeId);
@@ -231,7 +250,7 @@
   }
 
   public void putApproval(String label, short value) {
-    putApprovalFor(getUser().getAccountId(), label, value);
+    putApprovalFor(getAccountId(), label, value);
   }
 
   public void putApprovalFor(Account.Id reviewer, String label, short value) {
@@ -239,7 +258,7 @@
   }
 
   public void removeApproval(String label) {
-    removeApprovalFor(getUser().getAccountId(), label);
+    removeApprovalFor(getAccountId(), label);
   }
 
   public void removeApprovalFor(Account.Id reviewer, String label) {
@@ -276,6 +295,10 @@
     this.changeMessage = changeMessage;
   }
 
+  public void setTag(String tag) {
+    this.tag = tag;
+  }
+
   public void putComment(PatchLineComment c) {
     verifyComment(c);
     createDraftUpdateIfNull();
@@ -304,16 +327,17 @@
   @VisibleForTesting
   ChangeDraftUpdate createDraftUpdateIfNull() {
     if (draftUpdate == null) {
-      draftUpdate = draftUpdateFactory.create(ctl, when);
+      draftUpdate =
+          draftUpdateFactory.create(getNotes(), accountId, authorIdent, when);
     }
     return draftUpdate;
   }
 
   private void verifyComment(PatchLineComment c) {
     checkArgument(c.getRevId() != null, "RevId required for comment: %s", c);
-    checkArgument(c.getAuthor().equals(getUser().getAccountId()),
+    checkArgument(c.getAuthor().equals(getAccountId()),
         "The author for the following comment does not match the author of"
-        + " this ChangeDraftUpdate (%s): %s", getUser().getAccountId(), c);
+        + " this ChangeDraftUpdate (%s): %s", getAccountId(), c);
 
   }
 
@@ -375,6 +399,7 @@
 
     RevisionNoteBuilder.Cache cache = new RevisionNoteBuilder.Cache(rnm);
     for (PatchLineComment c : comments) {
+      c.setTag(tag);
       cache.get(c.getRevId()).putComment(c);
     }
     if (pushCert != null) {
@@ -403,16 +428,16 @@
       // parsed the revision notes. We can reuse them as long as the ref hasn't
       // advanced.
       ObjectId idFromNotes =
-          firstNonNull(ctl.getNotes().load().getRevision(), ObjectId.zeroId());
+          firstNonNull(getNotes().load().getRevision(), ObjectId.zeroId());
       if (idFromNotes.equals(curr)) {
-        return checkNotNull(ctl.getNotes().revisionNoteMap);
+        return checkNotNull(getNotes().revisionNoteMap);
       }
     }
     NoteMap noteMap = NoteMap.read(rw.getObjectReader(), rw.parseCommit(curr));
     // Even though reading from changes might not be enabled, we need to
     // parse any existing revision notes so we can merge them.
     return RevisionNoteMap.parse(
-        noteUtil, ctl.getId(), rw.getObjectReader(), noteMap, false);
+        noteUtil, getId(), rw.getObjectReader(), noteMap, false);
   }
 
   private void checkComments(Map<RevId, RevisionNote> existingNotes,
@@ -455,7 +480,7 @@
 
   @Override
   protected String getRefName() {
-    return ChangeNoteUtil.changeRefName(ctl.getId());
+    return ChangeNoteUtil.changeRefName(getId());
   }
 
   @Override
@@ -508,6 +533,10 @@
       addFooter(msg, FOOTER_HASHTAGS, comma.join(hashtags));
     }
 
+    if (tag != null) {
+      addFooter(msg, FOOTER_TAG, tag);
+    }
+
     if (groups != null) {
       addFooter(msg, FOOTER_GROUPS, comma.join(groups));
     }
@@ -527,7 +556,7 @@
             c.getRowKey(), c.getValue().get()).formatWithEquals());
       }
       Account.Id id = c.getColumnKey();
-      if (!id.equals(ctl.getUser().getAccountId())) {
+      if (!id.equals(getAccountId())) {
         addIdent(msg.append(' '), id);
       }
       msg.append('\n');
@@ -584,7 +613,7 @@
 
   @Override
   protected Project.NameKey getProjectName() {
-    return getProjectName(ctl);
+    return getChange().getProject();
   }
 
   @Override
@@ -603,7 +632,8 @@
         && topic == null
         && commit == null
         && psState == null
-        && groups == null;
+        && groups == null
+        && tag == null;
   }
 
   ChangeDraftUpdate getDraftUpdate() {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/DraftCommentNotes.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/DraftCommentNotes.java
index e7d933c..ba824a0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/DraftCommentNotes.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/DraftCommentNotes.java
@@ -52,6 +52,7 @@
 
   private final Change change;
   private final Account.Id author;
+  private final boolean autoRebuild;
 
   private ImmutableListMultimap<RevId, PatchLineComment> comments;
   private RevisionNoteMap revisionNoteMap;
@@ -61,9 +62,7 @@
       Args args,
       @Assisted Change change,
       @Assisted Account.Id author) {
-    super(args, change.getId());
-    this.change = change;
-    this.author = author;
+    this(args, change, author, true);
   }
 
   @AssistedInject
@@ -74,6 +73,18 @@
     super(args, changeId);
     this.change = null;
     this.author = author;
+    this.autoRebuild = true;
+  }
+
+  DraftCommentNotes(
+      Args args,
+      Change change,
+      Account.Id author,
+      boolean autoRebuild) {
+    super(args, change.getId());
+    this.change = change;
+    this.author = author;
+    this.autoRebuild = autoRebuild;
   }
 
   RevisionNoteMap getRevisionNoteMap() {
@@ -138,7 +149,7 @@
 
   @Override
   protected LoadHandle openHandle(Repository repo) throws IOException {
-    if (change != null) {
+    if (change != null && autoRebuild) {
       NoteDbChangeState state = NoteDbChangeState.parse(change);
       // Only check if this particular user's drafts are up to date, to avoid
       // reading unnecessary refs.
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/NoteDbChangeState.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/NoteDbChangeState.java
index 055cba9..6b62656 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/NoteDbChangeState.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/NoteDbChangeState.java
@@ -140,7 +140,7 @@
     return state;
   }
 
-  private static String toString(ObjectId changeMetaId,
+  public static String toString(ObjectId changeMetaId,
       Map<Account.Id, ObjectId> draftIds) {
     List<Account.Id> accountIds = Lists.newArrayList(draftIds.keySet());
     Collections.sort(accountIds, ReviewDbUtil.intKeyOrdering());
@@ -158,7 +158,7 @@
   private final ObjectId changeMetaId;
   private final ImmutableMap<Account.Id, ObjectId> draftIds;
 
-  NoteDbChangeState(Change.Id changeId, ObjectId changeMetaId,
+  public NoteDbChangeState(Change.Id changeId, ObjectId changeMetaId,
       Map<Account.Id, ObjectId> draftIds) {
     this.changeId = checkNotNull(changeId);
     this.changeMetaId = checkNotNull(changeMetaId);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/NoteDbUpdateManager.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/NoteDbUpdateManager.java
index 425072b..8344fed 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/NoteDbUpdateManager.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/NoteDbUpdateManager.java
@@ -55,8 +55,8 @@
 /**
  * Object to manage a single sequence of updates to NoteDb.
  * <p>
- * Instances are one-time-use. Handles updating both the change meta repo and
- * the All-Users meta repo for any affected changes, with proper ordering.
+ * Instances are one-time-use. Handles updating both the change repo and the
+ * All-Users repo for any affected changes, with proper ordering.
  * <p>
  * To see the state that would be applied prior to executing the full sequence
  * of updates, use {@link #stage()}.
@@ -104,7 +104,6 @@
   private final ListMultimap<String, ChangeUpdate> changeUpdates;
   private final ListMultimap<String, ChangeDraftUpdate> draftUpdates;
 
-  private OpenRepo codeRepo;
   private OpenRepo changeRepo;
   private OpenRepo allUsersRepo;
   private Map<Change.Id, NoteDbChangeState.Delta> staged;
@@ -131,12 +130,6 @@
     return this;
   }
 
-  public NoteDbUpdateManager setCodeRepo(Repository repo, RevWalk rw) {
-    checkState(codeRepo == null, "code repo already initialized");
-    codeRepo = new OpenRepo(repo, rw, null, null, false);
-    return this;
-  }
-
   public NoteDbUpdateManager setAllUsersRepo(Repository repo, RevWalk rw,
       ObjectInserter ins, ChainedReceiveCommands cmds) {
     checkState(allUsersRepo == null, "All-Users repo already initialized");
@@ -149,38 +142,25 @@
     return changeRepo;
   }
 
-  OpenRepo getCodeRepo() throws IOException {
-    initCodeRepo();
-    return codeRepo;
-  }
-
   OpenRepo getAllUsersRepo() throws IOException {
     initAllUsersRepo();
     return allUsersRepo;
   }
 
-  private void initCodeRepo() throws IOException {
-    if (codeRepo == null) {
-      codeRepo = openRepo(projectName, false);
-    }
-  }
-
   private void initChangeRepo() throws IOException {
     if (changeRepo == null) {
-      changeRepo = openRepo(projectName, true);
+      changeRepo = openRepo(projectName);
     }
   }
 
   private void initAllUsersRepo() throws IOException {
     if (allUsersRepo == null) {
-      allUsersRepo = openRepo(allUsersName, true);
+      allUsersRepo = openRepo(allUsersName);
     }
   }
 
-  private OpenRepo openRepo(Project.NameKey p, boolean meta) throws IOException {
-    Repository repo = meta
-        ? repoManager.openMetadataRepository(p)
-        : repoManager.openRepository(p);
+  private OpenRepo openRepo(Project.NameKey p) throws IOException {
+    Repository repo = repoManager.openRepository(p);
     ObjectInserter ins = repo.newObjectInserter();
     return new OpenRepo(repo, new RevWalk(ins.newReader()), ins,
         new ChainedReceiveCommands(), true);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RepoSequence.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RepoSequence.java
index 382b1eb..3d17131 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RepoSequence.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RepoSequence.java
@@ -129,7 +129,7 @@
   }
 
   private void acquire() throws OrmException {
-    try (Repository repo = repoManager.openMetadataRepository(projectName);
+    try (Repository repo = repoManager.openRepository(projectName);
         RevWalk rw = new RevWalk(repo)) {
       TryAcquire attempt = new TryAcquire(repo, rw);
       RefUpdate.Result result = retryer.call(attempt);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ReviewerStateInternal.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ReviewerStateInternal.java
index 3bf2135..be7f8d5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ReviewerStateInternal.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/ReviewerStateInternal.java
@@ -49,7 +49,7 @@
   private final FooterKey footerKey;
   private final ReviewerState state;
 
-  private ReviewerStateInternal(FooterKey footerKey, ReviewerState state) {
+  ReviewerStateInternal(FooterKey footerKey, ReviewerState state) {
     this.footerKey = footerKey;
     this.state = state;
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RevisionNote.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RevisionNote.java
index e6d7107..974538c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RevisionNote.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RevisionNote.java
@@ -60,18 +60,19 @@
     return new String(bytes, start, p.value);
   }
 
+  final byte[] raw;
   final ImmutableList<PatchLineComment> comments;
   final String pushCert;
 
   RevisionNote(ChangeNoteUtil noteUtil, Change.Id changeId,
       ObjectReader reader, ObjectId noteId, boolean draftsOnly)
       throws ConfigInvalidException, IOException {
-    byte[] bytes = reader.open(noteId, OBJ_BLOB).getCachedBytes(MAX_NOTE_SZ);
+    raw = reader.open(noteId, OBJ_BLOB).getCachedBytes(MAX_NOTE_SZ);
     MutableInteger p = new MutableInteger();
-    trimLeadingEmptyLines(bytes, p);
+    trimLeadingEmptyLines(raw, p);
     if (!draftsOnly) {
-      pushCert = parsePushCert(changeId, bytes, p);
-      trimLeadingEmptyLines(bytes, p);
+      pushCert = parsePushCert(changeId, raw, p);
+      trimLeadingEmptyLines(raw, p);
     } else {
       pushCert = null;
     }
@@ -79,6 +80,6 @@
         ? PatchLineComment.Status.DRAFT
         : PatchLineComment.Status.PUBLISHED;
     comments = ImmutableList.copyOf(
-        noteUtil.parseNote(bytes, p, changeId, status));
+        noteUtil.parseNote(raw, p, changeId, status));
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RevisionNoteBuilder.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RevisionNoteBuilder.java
index 5179146..4345e8b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RevisionNoteBuilder.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RevisionNoteBuilder.java
@@ -18,7 +18,6 @@
 import static com.google.gerrit.server.PatchLineCommentsUtil.PLC_ORDER;
 import static java.nio.charset.StandardCharsets.UTF_8;
 
-import com.google.common.collect.Iterables;
 import com.google.common.collect.Maps;
 import com.google.gerrit.reviewdb.client.PatchLineComment;
 import com.google.gerrit.reviewdb.client.RevId;
@@ -57,6 +56,7 @@
     }
   }
 
+  final byte[] baseRaw;
   final List<PatchLineComment> baseComments;
   final Map<PatchLineComment.Key, PatchLineComment> put;
   final Set<PatchLineComment.Key> delete;
@@ -65,10 +65,12 @@
 
   RevisionNoteBuilder(RevisionNote base) {
     if (base != null) {
+      baseRaw = base.raw;
       baseComments = base.comments;
       put = Maps.newHashMapWithExpectedSize(base.comments.size());
       pushCert = base.pushCert;
     } else {
+      baseRaw = new byte[0];
       baseComments = Collections.emptyList();
       put = new HashMap<>();
       pushCert = null;
@@ -101,7 +103,12 @@
 
     List<PatchLineComment> all =
         new ArrayList<>(baseComments.size() + put.size());
-    for (PatchLineComment c : Iterables.concat(baseComments, put.values())) {
+    for (PatchLineComment c : baseComments) {
+      if (!delete.contains(c.getKey()) && !put.containsKey(c.getKey())) {
+        all.add(c);
+      }
+    }
+    for (PatchLineComment c : put.values()) {
       if (!delete.contains(c.getKey())) {
         all.add(c);
       }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/AutoMerger.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/AutoMerger.java
new file mode 100644
index 0000000..ea4c921
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/AutoMerger.java
@@ -0,0 +1,231 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.patch;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import com.google.gerrit.reviewdb.client.RefNames;
+import com.google.gerrit.server.GerritPersonIdent;
+import com.google.inject.Inject;
+
+import org.eclipse.jgit.diff.Sequence;
+import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.dircache.DirCacheBuilder;
+import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.merge.MergeFormatter;
+import org.eclipse.jgit.merge.MergeResult;
+import org.eclipse.jgit.merge.ResolveMerger;
+import org.eclipse.jgit.merge.ThreeWayMergeStrategy;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevObject;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.util.TemporaryBuffer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+public class AutoMerger {
+  private static final Logger log = LoggerFactory.getLogger(AutoMerger.class);
+
+  private final PersonIdent gerritIdent;
+
+  @Inject
+  AutoMerger(@GerritPersonIdent PersonIdent gerritIdent) {
+    this.gerritIdent = gerritIdent;
+  }
+
+  /**
+   * Perform an auto-merge of the parents of the given merge commit.
+   *
+   * @return auto-merge commit or {@code null} if an auto-merge commit
+   *     couldn't be created. Headers of the returned RevCommit are parsed.
+   */
+  public RevCommit merge(Repository repo, RevWalk rw, RevCommit merge,
+      ThreeWayMergeStrategy mergeStrategy) throws IOException {
+    rw.parseHeaders(merge);
+    String hash = merge.name();
+    String refName = RefNames.REFS_CACHE_AUTOMERGE
+        + hash.substring(0, 2)
+        + "/"
+        + hash.substring(2);
+    Ref ref = repo.getRefDatabase().exactRef(refName);
+    if (ref != null && ref.getObjectId() != null) {
+      RevObject obj = rw.parseAny(ref.getObjectId());
+      if (obj instanceof RevCommit) {
+        return (RevCommit) obj;
+      }
+      return commit(repo, rw, refName, obj, merge);
+    }
+
+    ResolveMerger m = (ResolveMerger) mergeStrategy.newMerger(repo, true);
+    try (ObjectInserter ins = repo.newObjectInserter()) {
+      DirCache dc = DirCache.newInCore();
+      m.setDirCache(dc);
+      m.setObjectInserter(new ObjectInserter.Filter() {
+        @Override
+        protected ObjectInserter delegate() {
+          return ins;
+        }
+
+        @Override
+        public void flush() {
+        }
+
+        @Override
+        public void close() {
+        }
+      });
+
+      boolean couldMerge;
+      try {
+        couldMerge = m.merge(merge.getParents());
+      } catch (IOException e) {
+        // It is not safe to continue further down in this method as throwing
+        // an exception most likely means that the merge tree was not created
+        // and m.getMergeResults() is empty. This would mean that all paths are
+        // unmerged and Gerrit UI would show all paths in the patch list.
+        log.warn("Error attempting automerge " + refName, e);
+        return null;
+      }
+
+      ObjectId treeId;
+      if (couldMerge) {
+        treeId = m.getResultTreeId();
+
+      } else {
+        RevCommit ours = merge.getParent(0);
+        RevCommit theirs = merge.getParent(1);
+        rw.parseBody(ours);
+        rw.parseBody(theirs);
+        String oursMsg = ours.getShortMessage();
+        String theirsMsg = theirs.getShortMessage();
+
+        String oursName = String.format("HEAD   (%s %s)",
+            ours.abbreviate(6).name(),
+            oursMsg.substring(0, Math.min(oursMsg.length(), 60)));
+        String theirsName = String.format("BRANCH (%s %s)",
+            theirs.abbreviate(6).name(),
+            theirsMsg.substring(0, Math.min(theirsMsg.length(), 60)));
+
+        MergeFormatter fmt = new MergeFormatter();
+        Map<String, MergeResult<? extends Sequence>> r = m.getMergeResults();
+        Map<String, ObjectId> resolved = new HashMap<>();
+        for (Map.Entry<String, MergeResult<? extends Sequence>> entry : r.entrySet()) {
+          MergeResult<? extends Sequence> p = entry.getValue();
+          try (TemporaryBuffer buf =
+              new TemporaryBuffer.LocalFile(null, 10 * 1024 * 1024)) {
+            fmt.formatMerge(buf, p, "BASE", oursName, theirsName, UTF_8.name());
+            buf.close();
+
+            try (InputStream in = buf.openInputStream()) {
+              resolved.put(entry.getKey(), ins.insert(Constants.OBJ_BLOB, buf.length(), in));
+            }
+          }
+        }
+
+        DirCacheBuilder builder = dc.builder();
+        int cnt = dc.getEntryCount();
+        for (int i = 0; i < cnt;) {
+          DirCacheEntry entry = dc.getEntry(i);
+          if (entry.getStage() == 0) {
+            builder.add(entry);
+            i++;
+            continue;
+          }
+
+          int next = dc.nextEntry(i);
+          String path = entry.getPathString();
+          DirCacheEntry res = new DirCacheEntry(path);
+          if (resolved.containsKey(path)) {
+            // For a file with content merge conflict that we produced a result
+            // above on, collapse the file down to a single stage 0 with just
+            // the blob content, and a randomly selected mode (the lowest stage,
+            // which should be the merge base, or ours).
+            res.setFileMode(entry.getFileMode());
+            res.setObjectId(resolved.get(path));
+
+          } else if (next == i + 1) {
+            // If there is exactly one stage present, shouldn't be a conflict...
+            res.setFileMode(entry.getFileMode());
+            res.setObjectId(entry.getObjectId());
+
+          } else if (next == i + 2) {
+            // Two stages suggests a delete/modify conflict. Pick the higher
+            // stage as the automatic result.
+            entry = dc.getEntry(i + 1);
+            res.setFileMode(entry.getFileMode());
+            res.setObjectId(entry.getObjectId());
+
+          } else {
+            // 3 stage conflict, no resolve above
+            // Punt on the 3-stage conflict and show the base, for now.
+            res.setFileMode(entry.getFileMode());
+            res.setObjectId(entry.getObjectId());
+          }
+          builder.add(res);
+          i = next;
+        }
+        builder.finish();
+        treeId = dc.writeTree(ins);
+      }
+      ins.flush();
+
+      return commit(repo, rw, refName, treeId, merge);
+    }
+  }
+
+  private RevCommit commit(Repository repo, RevWalk rw, String refName,
+      ObjectId tree, RevCommit merge) throws IOException {
+    rw.parseHeaders(merge);
+    // For maximum stability, choose a single ident using the committer time of
+    // the input commit, using the server name and timezone.
+    PersonIdent ident = new PersonIdent(
+        gerritIdent,
+        merge.getCommitterIdent().getWhen(),
+        gerritIdent.getTimeZone());
+    CommitBuilder cb = new CommitBuilder();
+    cb.setAuthor(ident);
+    cb.setCommitter(ident);
+    cb.setTreeId(tree);
+    cb.setMessage("Auto-merge of " + merge.name() + '\n');
+    for (RevCommit p : merge.getParents()) {
+      cb.addParentId(p);
+    }
+    ObjectId commitId;
+    try (ObjectInserter ins = repo.newObjectInserter()) {
+      commitId = ins.insert(cb);
+      ins.flush();
+    }
+
+    RefUpdate ru = repo.updateRef(refName);
+    ru.setNewObjectId(commitId);
+    ru.disableRefLog();
+    ru.forceUpdate();
+
+    return rw.parseCommit(commitId);
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineDiff.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineDiff.java
index 46def59..60b97c7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineDiff.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineDiff.java
@@ -37,7 +37,7 @@
 public class IntraLineDiff implements Serializable {
   static final long serialVersionUID = IntraLineDiffKey.serialVersionUID;
 
-  public static enum Status implements CodedEnum {
+  public enum Status implements CodedEnum {
     EDIT_LIST('e'), DISABLED('D'), TIMEOUT('T'), ERROR('E');
 
     private final char code;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineLoader.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineLoader.java
index de70478..dd15cfc 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineLoader.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineLoader.java
@@ -40,7 +40,7 @@
 class IntraLineLoader implements Callable<IntraLineDiff> {
   static final Logger log = LoggerFactory.getLogger(IntraLineLoader.class);
 
-  static interface Factory {
+  interface Factory {
     IntraLineLoader create(IntraLineDiffKey key, IntraLineDiffArgs args);
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineWeigher.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineWeigher.java
index f6cff15..7088fe8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineWeigher.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineWeigher.java
@@ -21,8 +21,8 @@
     Weigher<IntraLineDiffKey, IntraLineDiff> {
   @Override
   public int weigh(IntraLineDiffKey key, IntraLineDiff value) {
-    return 16 + 8*8 + 2*36     // Size of IntraLineDiffKey, 64 bit JVM
-        + 16 + 2*8 + 16+8+4+20 // Size of IntraLineDiff, 64 bit JVM
-        + (8 + 16 + 4*4) * value.getEdits().size();
+    return 16 + 8 * 8 + 2 * 36     // Size of IntraLineDiffKey, 64 bit JVM
+        + 16 + 2 * 8 + 16 + 8 + 4 + 20 // Size of IntraLineDiff, 64 bit JVM
+        + (8 + 16 + 4 * 4) * value.getEdits().size();
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListEntry.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListEntry.java
index 2b5e235..3266f01 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListEntry.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListEntry.java
@@ -130,17 +130,17 @@
   }
 
   int weigh() {
-    int size = 16 + 6*8 + 2*4 + 20 + 16+8+4+20;
+    int size = 16 + 6 * 8 + 2 * 4 + 20 + 16 + 8 + 4 + 20;
     size += stringSize(oldName);
     size += stringSize(newName);
     size += header.length;
-    size += (8 + 16 + 4*4) * edits.size();
+    size += (8 + 16 + 4 * 4) * edits.size();
     return size;
   }
 
   private static int stringSize(String str) {
     if (str != null) {
-      return 16 + 3*4 + 16 + str.length() * 2;
+      return 16 + 3 * 4 + 16 + str.length() * 2;
     }
     return 0;
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListKey.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListKey.java
index 0200fa5..b04558d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListKey.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListKey.java
@@ -34,7 +34,7 @@
 import java.io.Serializable;
 
 public class PatchListKey implements Serializable {
-  static final long serialVersionUID = 19L;
+  static final long serialVersionUID = 20L;
 
   public static final BiMap<Whitespace, Character> WHITESPACE_TYPES = ImmutableBiMap.of(
       Whitespace.IGNORE_NONE, 'N',
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListLoader.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListLoader.java
index 63693e6..204c9ee 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListLoader.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListLoader.java
@@ -24,7 +24,6 @@
 import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
 import com.google.gerrit.reviewdb.client.Patch;
 import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.reviewdb.client.RefNames;
 import com.google.gerrit.server.config.ConfigUtil;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.git.GitRepositoryManager;
@@ -39,22 +38,13 @@
 import org.eclipse.jgit.diff.HistogramDiff;
 import org.eclipse.jgit.diff.RawText;
 import org.eclipse.jgit.diff.RawTextComparator;
-import org.eclipse.jgit.diff.Sequence;
-import org.eclipse.jgit.dircache.DirCache;
-import org.eclipse.jgit.dircache.DirCacheBuilder;
-import org.eclipse.jgit.dircache.DirCacheEntry;
 import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.FileMode;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectInserter;
 import org.eclipse.jgit.lib.ObjectReader;
-import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.RefUpdate;
 import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.merge.MergeFormatter;
-import org.eclipse.jgit.merge.MergeResult;
-import org.eclipse.jgit.merge.ResolveMerger;
 import org.eclipse.jgit.merge.ThreeWayMergeStrategy;
 import org.eclipse.jgit.patch.FileHeader;
 import org.eclipse.jgit.patch.FileHeader.PatchType;
@@ -63,18 +53,14 @@
 import org.eclipse.jgit.revwalk.RevTree;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.treewalk.TreeWalk;
-import org.eclipse.jgit.util.TemporaryBuffer;
 import org.eclipse.jgit.util.io.DisabledOutputStream;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
-import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
@@ -94,6 +80,7 @@
   private final PatchListCache patchListCache;
   private final ThreeWayMergeStrategy mergeStrategy;
   private final ExecutorService diffExecutor;
+  private final AutoMerger autoMerger;
   private final PatchListKey key;
   private final Project.NameKey project;
   private final long timeoutMillis;
@@ -104,12 +91,14 @@
       PatchListCache plc,
       @GerritServerConfig Config cfg,
       @DiffExecutor ExecutorService de,
+      AutoMerger am,
       @Assisted PatchListKey k,
       @Assisted Project.NameKey p) {
     repoManager = mgr;
     patchListCache = plc;
     mergeStrategy = MergeUtil.getMergeStrategy(cfg);
     diffExecutor = de;
+    autoMerger = am;
     key = k;
     project = p;
     lock = new Object();
@@ -344,153 +333,13 @@
         return r;
       }
       case 2:
-        return automerge(repo, rw, b, mergeStrategy);
+        return autoMerger.merge(repo, rw, b, mergeStrategy);
       default:
         // TODO(sop) handle an octopus merge.
         return null;
     }
   }
 
-  public static RevTree automerge(Repository repo, RevWalk rw, RevCommit b,
-      ThreeWayMergeStrategy mergeStrategy) throws IOException {
-    return automerge(repo, rw, b, mergeStrategy, true);
-  }
-
-  public static RevTree automerge(Repository repo, RevWalk rw, RevCommit b,
-      ThreeWayMergeStrategy mergeStrategy, boolean save) throws IOException {
-    String hash = b.name();
-    String refName = RefNames.REFS_CACHE_AUTOMERGE
-        + hash.substring(0, 2)
-        + "/"
-        + hash.substring(2);
-    Ref ref = repo.getRefDatabase().exactRef(refName);
-    if (ref != null && ref.getObjectId() != null) {
-      return rw.parseTree(ref.getObjectId());
-    }
-
-    ResolveMerger m = (ResolveMerger) mergeStrategy.newMerger(repo, true);
-    try (ObjectInserter ins = repo.newObjectInserter()) {
-      DirCache dc = DirCache.newInCore();
-      m.setDirCache(dc);
-      m.setObjectInserter(new ObjectInserter.Filter() {
-        @Override
-        protected ObjectInserter delegate() {
-          return ins;
-        }
-
-        @Override
-        public void flush() {
-        }
-
-        @Override
-        public void close() {
-        }
-      });
-
-      boolean couldMerge;
-      try {
-        couldMerge = m.merge(b.getParents());
-      } catch (IOException e) {
-        // It is not safe to continue further down in this method as throwing
-        // an exception most likely means that the merge tree was not created
-        // and m.getMergeResults() is empty. This would mean that all paths are
-        // unmerged and Gerrit UI would show all paths in the patch list.
-        log.warn("Error attempting automerge " + refName, e);
-        return null;
-      }
-
-      ObjectId treeId;
-      if (couldMerge) {
-        treeId = m.getResultTreeId();
-
-      } else {
-        RevCommit ours = b.getParent(0);
-        RevCommit theirs = b.getParent(1);
-        rw.parseBody(ours);
-        rw.parseBody(theirs);
-        String oursMsg = ours.getShortMessage();
-        String theirsMsg = theirs.getShortMessage();
-
-        String oursName = String.format("HEAD   (%s %s)",
-            ours.abbreviate(6).name(),
-            oursMsg.substring(0, Math.min(oursMsg.length(), 60)));
-        String theirsName = String.format("BRANCH (%s %s)",
-            theirs.abbreviate(6).name(),
-            theirsMsg.substring(0, Math.min(theirsMsg.length(), 60)));
-
-        MergeFormatter fmt = new MergeFormatter();
-        Map<String, MergeResult<? extends Sequence>> r = m.getMergeResults();
-        Map<String, ObjectId> resolved = new HashMap<>();
-        for (Map.Entry<String, MergeResult<? extends Sequence>> entry : r.entrySet()) {
-          MergeResult<? extends Sequence> p = entry.getValue();
-          try (TemporaryBuffer buf =
-              new TemporaryBuffer.LocalFile(null, 10 * 1024 * 1024)) {
-            fmt.formatMerge(buf, p, "BASE", oursName, theirsName, UTF_8.name());
-            buf.close();
-
-            try (InputStream in = buf.openInputStream()) {
-              resolved.put(entry.getKey(), ins.insert(Constants.OBJ_BLOB, buf.length(), in));
-            }
-          }
-        }
-
-        DirCacheBuilder builder = dc.builder();
-        int cnt = dc.getEntryCount();
-        for (int i = 0; i < cnt;) {
-          DirCacheEntry entry = dc.getEntry(i);
-          if (entry.getStage() == 0) {
-            builder.add(entry);
-            i++;
-            continue;
-          }
-
-          int next = dc.nextEntry(i);
-          String path = entry.getPathString();
-          DirCacheEntry res = new DirCacheEntry(path);
-          if (resolved.containsKey(path)) {
-            // For a file with content merge conflict that we produced a result
-            // above on, collapse the file down to a single stage 0 with just
-            // the blob content, and a randomly selected mode (the lowest stage,
-            // which should be the merge base, or ours).
-            res.setFileMode(entry.getFileMode());
-            res.setObjectId(resolved.get(path));
-
-          } else if (next == i + 1) {
-            // If there is exactly one stage present, shouldn't be a conflict...
-            res.setFileMode(entry.getFileMode());
-            res.setObjectId(entry.getObjectId());
-
-          } else if (next == i + 2) {
-            // Two stages suggests a delete/modify conflict. Pick the higher
-            // stage as the automatic result.
-            entry = dc.getEntry(i + 1);
-            res.setFileMode(entry.getFileMode());
-            res.setObjectId(entry.getObjectId());
-
-          } else { // 3 stage conflict, no resolve above
-            // Punt on the 3-stage conflict and show the base, for now.
-            res.setFileMode(entry.getFileMode());
-            res.setObjectId(entry.getObjectId());
-          }
-          builder.add(res);
-          i = next;
-        }
-        builder.finish();
-        treeId = dc.writeTree(ins);
-      }
-      ins.flush();
-
-      if (save) {
-        RefUpdate update = repo.updateRef(refName);
-        update.setNewObjectId(treeId);
-        update.disableRefLog();
-        update.forceUpdate();
-      }
-
-      return rw.lookupTree(treeId);
-    }
-  }
-
   private static ObjectId emptyTree(final Repository repo) throws IOException {
     try (ObjectInserter oi = repo.newObjectInserter()) {
       ObjectId id = oi.insert(Constants.OBJ_TREE, new byte[] {});
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListWeigher.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListWeigher.java
index d715246..2362986 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListWeigher.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListWeigher.java
@@ -20,8 +20,8 @@
 public class PatchListWeigher implements Weigher<PatchListKey, PatchList> {
   @Override
   public int weigh(PatchListKey key, PatchList value) {
-    int size = 16 + 4*8 + 2*36 // Size of PatchListKey, 64 bit JVM
-        + 16 + 3*8 + 3*4 + 20; // Size of PatchList, 64 bit JVM
+    int size = 16 + 4 * 8 + 2 * 36 // Size of PatchListKey, 64 bit JVM
+        + 16 + 3 * 8 + 3 * 4 + 20; // Size of PatchList, 64 bit JVM
     for (PatchListEntry e : value.getPatches()) {
       size += e.weigh();
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/AutoRegisterModules.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/AutoRegisterModules.java
index 0eaddb3..f719e8d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/AutoRegisterModules.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/AutoRegisterModules.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.server.plugins;
 
+import static com.google.gerrit.extensions.webui.JavaScriptPlugin.STATIC_INIT_JS;
 import static com.google.gerrit.server.plugins.AutoRegisterUtil.calculateBindAnnotation;
 import static com.google.gerrit.server.plugins.PluginGuiceEnvironment.is;
 
@@ -23,7 +24,9 @@
 import com.google.gerrit.extensions.annotations.Export;
 import com.google.gerrit.extensions.annotations.ExtensionPoint;
 import com.google.gerrit.extensions.annotations.Listen;
+import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.gerrit.extensions.webui.JavaScriptPlugin;
+import com.google.gerrit.extensions.webui.WebUiPlugin;
 import com.google.gerrit.server.plugins.PluginContentScanner.ExtensionMetaData;
 import com.google.inject.AbstractModule;
 import com.google.inject.Module;
@@ -48,10 +51,11 @@
   private final PluginContentScanner scanner;
   private final ClassLoader classLoader;
   private final ModuleGenerator sshGen;
-  private final HttpModuleGenerator httpGen;
+  private final ModuleGenerator httpGen;
 
   private Set<Class<?>> sysSingletons;
   private Multimap<TypeLiteral<?>, Class<?>> sysListen;
+  private String initJs;
 
   Module sysModule;
   Module sshModule;
@@ -70,19 +74,20 @@
         : new ModuleGenerator.NOP();
     this.httpGen = env.hasHttpModule()
         ? env.newHttpModuleGenerator()
-        : new HttpModuleGenerator.NOP();
+        : new ModuleGenerator.NOP();
   }
 
   AutoRegisterModules discover() throws InvalidPluginException {
     sysSingletons = Sets.newHashSet();
     sysListen = LinkedListMultimap.create();
+    initJs = null;
 
     sshGen.setPluginName(pluginName);
     httpGen.setPluginName(pluginName);
 
     scan();
 
-    if (!sysSingletons.isEmpty() || !sysListen.isEmpty()) {
+    if (!sysSingletons.isEmpty() || !sysListen.isEmpty() || initJs != null) {
       sysModule = makeSystemModule();
     }
     sshModule = sshGen.create();
@@ -107,6 +112,10 @@
           Annotation n = calculateBindAnnotation(impl);
           bind(type).annotatedWith(n).to(impl);
         }
+        if (initJs != null) {
+          DynamicSet.bind(binder(), WebUiPlugin.class)
+              .toInstance(new JavaScriptPlugin(initJs));
+        }
       }
     };
   }
@@ -120,18 +129,20 @@
     for (ExtensionMetaData listener : extensions.get(Listen.class)) {
       listen(listener);
     }
-    exportInitJs();
+    if (env.hasHttpModule()) {
+      exportInitJs();
+    }
   }
 
   private void exportInitJs() {
     try {
-      if (scanner.getEntry(JavaScriptPlugin.STATIC_INIT_JS).isPresent()) {
-        httpGen.export(JavaScriptPlugin.INIT_JS);
+      if (scanner.getEntry(STATIC_INIT_JS).isPresent()) {
+        initJs = STATIC_INIT_JS;
       }
     } catch (IOException e) {
       log.warn(String.format("Cannot access %s from plugin %s: "
           + "JavaScript auto-discovered plugin will not be registered",
-          JavaScriptPlugin.STATIC_INIT_JS, pluginName), e);
+          STATIC_INIT_JS, pluginName), e);
     }
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/HttpModuleGenerator.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/HttpModuleGenerator.java
deleted file mode 100644
index dd0ce67..0000000
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/HttpModuleGenerator.java
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (C) 2014 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.server.plugins;
-
-
-public interface HttpModuleGenerator extends ModuleGenerator {
-  void export(String javascript);
-
-  static class NOP extends ModuleGenerator.NOP
-      implements HttpModuleGenerator {
-    @Override
-    public void export(String javascript) {
-      // do nothing
-    }
-  }
-}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/JsPlugin.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/JsPlugin.java
index ea81f17..544cc5b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/JsPlugin.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/JsPlugin.java
@@ -30,7 +30,7 @@
 import java.nio.file.Path;
 
 class JsPlugin extends Plugin {
-  private Injector httpInjector;
+  private Injector sysInjector;
 
   JsPlugin(String name, Path srcFile, PluginUser pluginUser,
       FileSnapshot snapshot) {
@@ -52,7 +52,7 @@
   public void start(PluginGuiceEnvironment env) throws Exception {
     manager = new LifecycleManager();
     String fileName = getSrcFile().getFileName().toString();
-    httpInjector =
+    sysInjector =
         Guice.createInjector(new StandaloneJsPluginModule(getName(), fileName));
     manager.start();
   }
@@ -61,13 +61,13 @@
   protected void stop(PluginGuiceEnvironment env) {
     if (manager != null) {
       manager.stop();
-      httpInjector = null;
+      sysInjector = null;
     }
   }
 
   @Override
   public Injector getSysInjector() {
-    return null;
+    return sysInjector;
   }
 
   @Override
@@ -79,7 +79,7 @@
   @Override
   @Nullable
   public Injector getHttpInjector() {
-    return httpInjector;
+    return null;
   }
 
   @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ModuleGenerator.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ModuleGenerator.java
index ae8bb0c..7818591 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ModuleGenerator.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ModuleGenerator.java
@@ -27,7 +27,7 @@
 
   Module create() throws InvalidPluginException;
 
-  static class NOP implements ModuleGenerator {
+  class NOP implements ModuleGenerator {
 
     @Override
     public void setPluginName(String name) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/Plugin.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/Plugin.java
index 588bc6d..3154b4e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/Plugin.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/Plugin.java
@@ -32,7 +32,7 @@
 import java.util.jar.Manifest;
 
 public abstract class Plugin {
-  public static enum ApiType {
+  public enum ApiType {
     EXTENSION, PLUGIN, JS
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginContentScanner.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginContentScanner.java
index 1d9cd0e..15bb92f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginContentScanner.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginContentScanner.java
@@ -74,7 +74,7 @@
    * provided by a plugin to extend an existing
    * extension point in Gerrit.
    */
-  public static class ExtensionMetaData {
+  class ExtensionMetaData {
     public final String className;
     public final String annotationValue;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginGuiceEnvironment.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginGuiceEnvironment.java
index 87eca8b..bc471e4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginGuiceEnvironment.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginGuiceEnvironment.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.server.plugins;
 
+import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.gerrit.extensions.registration.PrivateInternals_DynamicTypes.dynamicItemsOf;
 import static com.google.gerrit.extensions.registration.PrivateInternals_DynamicTypes.dynamicMapsOf;
 import static com.google.gerrit.extensions.registration.PrivateInternals_DynamicTypes.dynamicSetsOf;
@@ -34,6 +35,7 @@
 import com.google.gerrit.extensions.registration.RegistrationHandle;
 import com.google.gerrit.extensions.registration.ReloadableRegistrationHandle;
 import com.google.gerrit.extensions.systemstatus.ServerInformation;
+import com.google.gerrit.extensions.webui.WebUiPlugin;
 import com.google.gerrit.metrics.MetricMaker;
 import com.google.gerrit.server.util.PluginRequestContext;
 import com.google.gerrit.server.util.RequestContext;
@@ -52,6 +54,8 @@
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.ParameterizedType;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -85,7 +89,7 @@
   private Module httpModule;
 
   private Provider<ModuleGenerator> sshGen;
-  private Provider<HttpModuleGenerator> httpGen;
+  private Provider<ModuleGenerator> httpGen;
 
   private Map<TypeLiteral<?>, DynamicItem<?>> sysItems;
   private Map<TypeLiteral<?>, DynamicItem<?>> sshItems;
@@ -197,15 +201,27 @@
 
   public void setHttpInjector(Injector injector) {
     httpModule = copy(injector);
-    httpGen = injector.getProvider(HttpModuleGenerator.class);
+    httpGen = injector.getProvider(ModuleGenerator.class);
     httpItems = dynamicItemsOf(injector);
-    httpSets = dynamicSetsOf(injector);
+    httpSets = httpDynamicSetsOf(injector);
     httpMaps = dynamicMapsOf(injector);
     onStart.addAll(listeners(injector, StartPluginListener.class));
     onStop.addAll(listeners(injector, StopPluginListener.class));
     onReload.addAll(listeners(injector, ReloadPluginListener.class));
   }
 
+  private Map<TypeLiteral<?>, DynamicSet<?>> httpDynamicSetsOf(Injector i) {
+    // Copy binding of DynamicSet<WebUiPlugin> from sysInjector to HTTP.
+    // This supports older plugins that bound a plugin in the HttpModule.
+    TypeLiteral<WebUiPlugin> key = TypeLiteral.get(WebUiPlugin.class);
+    DynamicSet<?> web = sysSets.get(key);
+    checkNotNull(web, "DynamicSet<WebUiPlugin> exists in sysInjector");
+
+    Map<TypeLiteral<?>, DynamicSet<?>> m = new HashMap<>(dynamicSetsOf(i));
+    m.put(key, web);
+    return Collections.unmodifiableMap(m);
+  }
+
   boolean hasHttpModule() {
     return httpModule != null;
   }
@@ -214,7 +230,7 @@
     return httpModule;
   }
 
-  HttpModuleGenerator newHttpModuleGenerator() {
+  ModuleGenerator newHttpModuleGenerator() {
     return httpGen.get();
   }
 
@@ -472,7 +488,7 @@
   private static <T> void replace(Plugin newPlugin,
       ReloadableRegistrationHandle<T> h, Binding<T> b) {
     RegistrationHandle n = h.replace(b.getKey(), b.getProvider());
-    if (n != null){
+    if (n != null) {
       newPlugin.add(n);
     }
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginLoader.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginLoader.java
index 5006401..0ea7bd2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginLoader.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginLoader.java
@@ -623,7 +623,7 @@
     for (String name : pluginPaths.keys()) {
       for (Path pluginPath : pluginPaths.asMap().get(name)) {
         if (!pluginPath.getFileName().toString().endsWith(".disabled")) {
-          assert(!activePlugins.containsKey(name));
+          assert !activePlugins.containsKey(name);
           activePlugins.put(name, pluginPath);
         }
       }
@@ -656,7 +656,7 @@
         continue;
       }
       Path winner = Iterables.getFirst(enabled, null);
-      assert(winner != null);
+      assert winner != null;
       // Disable all loser plugins by renaming their file names to
       // "file.disabled" and replace the disabled files in the multimap.
       Collection<Path> elementsToRemove = Lists.newArrayList();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ServerPlugin.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ServerPlugin.java
index 1ae9351..de1966f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ServerPlugin.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ServerPlugin.java
@@ -100,7 +100,7 @@
       this.sysModule = load(sysName, classLoader);
       this.sshModule = load(sshName, classLoader);
       this.httpModule = load(httpName, classLoader);
-    } catch(ClassNotFoundException e) {
+    } catch (ClassNotFoundException e) {
       throw new InvalidPluginException("Unable to load plugin Guice Modules", e);
     }
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ServerPluginProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ServerPluginProvider.java
index bc2432b..068d73c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ServerPluginProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ServerPluginProvider.java
@@ -37,7 +37,7 @@
   /**
    * Descriptor of the Plugin that ServerPluginProvider has to load.
    */
-  public class PluginDescription {
+  class PluginDescription {
     public final PluginUser user;
     public final String canonicalUrl;
     public final Path dataDir;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java
index 83f69ee..bc4d8f3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java
@@ -64,7 +64,7 @@
     public String revision;
   }
 
-  public static interface Factory {
+  public interface Factory {
     CreateBranch create(String ref);
   }
 
@@ -259,7 +259,7 @@
 
     public static final String MESSAGE = "Invalid Revision";
 
-    public InvalidRevisionException() {
+    InvalidRevisionException() {
       super(MESSAGE);
     }
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateProject.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateProject.java
index fec858a..a73ed0e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateProject.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateProject.java
@@ -80,7 +80,7 @@
 
 @RequiresCapability(GlobalCapability.CREATE_PROJECT)
 public class CreateProject implements RestModifyView<TopLevelResource, ProjectInput> {
-  public static interface Factory {
+  public interface Factory {
     CreateProject create(String name);
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranch.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranch.java
index bda2c71..b4c25b4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranch.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranch.java
@@ -39,7 +39,7 @@
 import java.io.IOException;
 
 @Singleton
-public class DeleteBranch implements RestModifyView<BranchResource, Input>{
+public class DeleteBranch implements RestModifyView<BranchResource, Input> {
   private static final Logger log = LoggerFactory.getLogger(DeleteBranch.class);
   private static final int MAX_LOCK_FAILURE_CALLS = 10;
   private static final long SLEEP_ON_LOCK_FAILURE_MS = 15;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java
index b0ab94b..907b925 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java
@@ -76,7 +76,7 @@
 public class ListProjects implements RestReadView<TopLevelResource> {
   private static final Logger log = LoggerFactory.getLogger(ListProjects.class);
 
-  public static enum FilterType {
+  public enum FilterType {
     CODE {
       @Override
       boolean matches(Repository git) throws IOException {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
index 8922df5..dd57ed4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
@@ -473,8 +473,8 @@
   }
 
   private static class AllowedRange {
-    private int allowMin = 0;
-    private int allowMax = 0;
+    private int allowMin;
+    private int allowMax;
     private int blockMin = Integer.MIN_VALUE;
     private int blockMax = Integer.MAX_VALUE;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/RepositoryStatistics.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/RepositoryStatistics.java
index d8294c0..de045b7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/RepositoryStatistics.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/RepositoryStatistics.java
@@ -23,7 +23,7 @@
 class RepositoryStatistics extends TreeMap<String, Object> {
   private static final long serialVersionUID = 1L;
 
-  public RepositoryStatistics(Properties p) {
+  RepositoryStatistics(Properties p) {
     for (Entry<Object, Object> e : p.entrySet()) {
       put(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE,
           e.getKey().toString()), e.getValue());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/SetHead.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/SetHead.java
index 571ddb3..aa06024 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/SetHead.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/SetHead.java
@@ -90,7 +90,7 @@
         final RefUpdate u = repo.updateRef(Constants.HEAD, true);
         u.setRefLogIdent(identifiedUser.get().newRefLogIdent());
         RefUpdate.Result res = u.link(newHead);
-        switch(res) {
+        switch (res) {
           case NO_CHANGE:
           case RENAMED:
           case FORCED:
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
index 2ea7e82..7e6537c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
@@ -83,7 +83,7 @@
   private static class UserTermExpected extends Exception {
     private static final long serialVersionUID = 1L;
 
-    public UserTermExpected(SubmitRecord.Label label) {
+    UserTermExpected(SubmitRecord.Label label) {
       super(String.format("A label with the status %s must contain a user.",
           label.toString()));
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
index 40fadb4..452d51f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
@@ -44,6 +44,7 @@
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.PatchLineCommentsUtil;
 import com.google.gerrit.server.PatchSetUtil;
+import com.google.gerrit.server.StarredChangesUtil;
 import com.google.gerrit.server.change.MergeabilityCache;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.MergeUtil;
@@ -296,7 +297,7 @@
   public static ChangeData createForTest(Project.NameKey project, Change.Id id,
       int currentPatchSetId) {
     ChangeData cd = new ChangeData(null, null, null, null, null, null, null,
-        null, null, null, null, null, null, null, project, id);
+        null, null, null, null, null, null, null, null, project, id);
     cd.currentPatchSet = new PatchSet(new PatchSet.Id(id, currentPatchSetId));
     return cd;
   }
@@ -315,6 +316,7 @@
   private final PatchListCache patchListCache;
   private final NotesMigration notesMigration;
   private final MergeabilityCache mergeabilityCache;
+  private final StarredChangesUtil starredChangesUtil;
   private final Change.Id legacyId;
   private DataSource<ChangeData> returnedBySource;
   private Project.NameKey project;
@@ -338,6 +340,7 @@
   private Set<Account.Id> editsByUser;
   private Set<Account.Id> reviewedBy;
   private Set<Account.Id> draftsByUser;
+  private Set<Account.Id> starredByUser;
   private PersonIdent author;
   private PersonIdent committer;
 
@@ -356,6 +359,7 @@
       PatchListCache patchListCache,
       NotesMigration notesMigration,
       MergeabilityCache mergeabilityCache,
+      StarredChangesUtil starredChangesUtil,
       @Assisted ReviewDb db,
       @Assisted Project.NameKey project,
       @Assisted Change.Id id) {
@@ -373,6 +377,7 @@
     this.patchListCache = patchListCache;
     this.notesMigration = notesMigration;
     this.mergeabilityCache = mergeabilityCache;
+    this.starredChangesUtil = starredChangesUtil;
     this.project = project;
     this.legacyId = id;
   }
@@ -392,6 +397,7 @@
       PatchListCache patchListCache,
       NotesMigration notesMigration,
       MergeabilityCache mergeabilityCache,
+      StarredChangesUtil starredChangesUtil,
       @Assisted ReviewDb db,
       @Assisted Change c) {
     this.db = db;
@@ -408,6 +414,7 @@
     this.patchListCache = patchListCache;
     this.notesMigration = notesMigration;
     this.mergeabilityCache = mergeabilityCache;
+    this.starredChangesUtil = starredChangesUtil;
     legacyId = c.getId();
     change = c;
     project = c.getProject();
@@ -428,6 +435,7 @@
       PatchListCache patchListCache,
       NotesMigration notesMigration,
       MergeabilityCache mergeabilityCache,
+      StarredChangesUtil starredChangesUtil,
       @Assisted ReviewDb db,
       @Assisted ChangeNotes cn) {
     this.db = db;
@@ -444,6 +452,7 @@
     this.patchListCache = patchListCache;
     this.notesMigration = notesMigration;
     this.mergeabilityCache = mergeabilityCache;
+    this.starredChangesUtil = starredChangesUtil;
     legacyId = cn.getChangeId();
     change = cn.getChange();
     project = cn.getProjectName();
@@ -465,6 +474,7 @@
       PatchListCache patchListCache,
       NotesMigration notesMigration,
       MergeabilityCache mergeabilityCache,
+      StarredChangesUtil starredChangesUtil,
       @Assisted ReviewDb db,
       @Assisted ChangeControl c) {
     this.db = db;
@@ -481,6 +491,7 @@
     this.patchListCache = patchListCache;
     this.notesMigration = notesMigration;
     this.mergeabilityCache = mergeabilityCache;
+    this.starredChangesUtil = starredChangesUtil;
     legacyId = c.getId();
     change = c.getChange();
     changeControl = c;
@@ -503,6 +514,7 @@
       PatchListCache patchListCache,
       NotesMigration notesMigration,
       MergeabilityCache mergeabilityCache,
+      StarredChangesUtil starredChangesUtil,
       @Assisted ReviewDb db,
       @Assisted Change.Id id) {
     checkState(!notesMigration.readChanges(),
@@ -521,6 +533,7 @@
     this.patchListCache = patchListCache;
     this.notesMigration = notesMigration;
     this.mergeabilityCache = mergeabilityCache;
+    this.starredChangesUtil = starredChangesUtil;
     this.legacyId = id;
     this.project = null;
   }
@@ -1005,6 +1018,17 @@
     this.reviewedBy = reviewedBy;
   }
 
+  public Set<Account.Id> starredBy() throws OrmException {
+    if (starredByUser == null) {
+      starredByUser = starredChangesUtil.byChange(legacyId);
+    }
+    return starredByUser;
+  }
+
+  public void setStarredBy(Set<Account.Id> starredByUser) {
+    this.starredByUser = starredByUser;
+  }
+
   @AutoValue
   abstract static class ReviewedByEvent {
     private static ReviewedByEvent create(ChangeMessage msg) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
index cb27de4..2679f29 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
@@ -419,7 +419,7 @@
   @Operator
   public Predicate<ChangeData> has(String value) throws QueryParseException {
     if ("star".equalsIgnoreCase(value)) {
-      return new IsStarredByPredicate(args);
+      return starredby(self());
     }
 
     if ("draft".equalsIgnoreCase(value)) {
@@ -435,7 +435,7 @@
   @Operator
   public Predicate<ChangeData> is(String value) throws QueryParseException {
     if ("starred".equalsIgnoreCase(value)) {
-      return new IsStarredByPredicate(args);
+      return starredby(self());
     }
 
     if ("watched".equalsIgnoreCase(value)) {
@@ -648,17 +648,25 @@
   @Operator
   public Predicate<ChangeData> starredby(String who)
       throws QueryParseException, OrmException {
-    if ("self".equals(who)) {
-      return new IsStarredByPredicate(args);
-    }
-    Set<Account.Id> m = parseAccount(who);
-    List<IsStarredByPredicate> p = Lists.newArrayListWithCapacity(m.size());
-    for (Account.Id id : m) {
-      p.add(new IsStarredByPredicate(args.asUser(id)));
+    return starredby(parseAccount(who));
+  }
+
+  private Predicate<ChangeData> starredby(Set<Account.Id> who)
+      throws QueryParseException {
+    List<Predicate<ChangeData>> p = Lists.newArrayListWithCapacity(who.size());
+    for (Account.Id id : who) {
+      p.add(starredby(id));
     }
     return Predicate.or(p);
   }
 
+  private Predicate<ChangeData> starredby(Account.Id who)
+      throws QueryParseException {
+    return args.getSchema().hasField(ChangeField.STARREDBY)
+        ? new IsStarredByPredicate(who)
+        : new IsStarredByLegacyPredicate(args.asUser(who));
+  }
+
   @Operator
   public Predicate<ChangeData> watchedby(String who)
       throws QueryParseException, OrmException {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/InternalChangeQuery.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/InternalChangeQuery.java
index bb72a1b..37cdfaf 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/InternalChangeQuery.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/InternalChangeQuery.java
@@ -28,6 +28,7 @@
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import com.google.gerrit.common.Nullable;
+import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.Branch;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.Project;
@@ -297,6 +298,10 @@
     return query(and(project(project), or(groupPredicates)));
   }
 
+  public List<ChangeData> byIsStarred(Account.Id id) throws OrmException {
+    return query(new IsStarredByPredicate(id));
+  }
+
   public List<ChangeData> query(Predicate<ChangeData> p) throws OrmException {
     try {
       return qp.queryChanges(p).changes();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsStarredByLegacyPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsStarredByLegacyPredicate.java
new file mode 100644
index 0000000..718c3f6
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsStarredByLegacyPredicate.java
@@ -0,0 +1,71 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.query.change;
+
+import com.google.common.collect.Lists;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.query.OrPredicate;
+import com.google.gerrit.server.query.Predicate;
+import com.google.gerrit.server.query.QueryParseException;
+import com.google.gerrit.server.query.change.ChangeQueryBuilder.Arguments;
+
+import java.util.List;
+import java.util.Set;
+
+@Deprecated
+class IsStarredByLegacyPredicate extends OrPredicate<ChangeData> {
+  private static String describe(CurrentUser user) {
+    if (user.isIdentifiedUser()) {
+      return user.getAccountId().toString();
+    }
+    return user.toString();
+  }
+
+  private static List<Predicate<ChangeData>> predicates(Set<Change.Id> ids) {
+    List<Predicate<ChangeData>> r = Lists.newArrayListWithCapacity(ids.size());
+    for (Change.Id id : ids) {
+      r.add(new LegacyChangeIdPredicate(id));
+    }
+    return r;
+  }
+
+  private final CurrentUser user;
+
+  IsStarredByLegacyPredicate(Arguments args) throws QueryParseException {
+    super(predicates(args.getIdentifiedUser().getStarredChanges()));
+    this.user = args.getIdentifiedUser();
+  }
+
+  @Override
+  public boolean match(final ChangeData object) {
+    return user.getStarredChanges().contains(object.getId());
+  }
+
+  @Override
+  public int getCost() {
+    return 0;
+  }
+
+  @Override
+  public String toString() {
+    String val = describe(user);
+    if (val.indexOf(' ') < 0) {
+      return ChangeQueryBuilder.FIELD_STARREDBY + ":" + val;
+    } else {
+      return ChangeQueryBuilder.FIELD_STARREDBY + ":\"" + val + "\"";
+    }
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsStarredByPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsStarredByPredicate.java
index 5ff859a..50c54f6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsStarredByPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsStarredByPredicate.java
@@ -14,57 +14,31 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.common.collect.Lists;
-import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.server.CurrentUser;
-import com.google.gerrit.server.query.OrPredicate;
-import com.google.gerrit.server.query.Predicate;
-import com.google.gerrit.server.query.QueryParseException;
-import com.google.gerrit.server.query.change.ChangeQueryBuilder.Arguments;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
+import com.google.gwtorm.server.OrmException;
 
-import java.util.List;
-import java.util.Set;
+class IsStarredByPredicate extends IndexPredicate<ChangeData> {
+  private final Account.Id accountId;
 
-class IsStarredByPredicate extends OrPredicate<ChangeData> {
-  private static String describe(CurrentUser user) {
-    if (user.isIdentifiedUser()) {
-      return user.getAccountId().toString();
-    }
-    return user.toString();
-  }
-
-  private static List<Predicate<ChangeData>> predicates(Set<Change.Id> ids) {
-    List<Predicate<ChangeData>> r = Lists.newArrayListWithCapacity(ids.size());
-    for (Change.Id id : ids) {
-      r.add(new LegacyChangeIdPredicate(id));
-    }
-    return r;
-  }
-
-  private final CurrentUser user;
-
-  IsStarredByPredicate(Arguments args) throws QueryParseException {
-    super(predicates(args.getIdentifiedUser().getStarredChanges()));
-    this.user = args.getIdentifiedUser();
+  IsStarredByPredicate(Account.Id accountId) {
+    super(ChangeField.STARREDBY, accountId.toString());
+    this.accountId = accountId;
   }
 
   @Override
-  public boolean match(final ChangeData object) {
-    return user.getStarredChanges().contains(object.getId());
+  public boolean match(ChangeData cd) throws OrmException {
+    return cd.starredBy().contains(accountId);
   }
 
   @Override
   public int getCost() {
-    return 0;
+    return 1;
   }
 
   @Override
   public String toString() {
-    String val = describe(user);
-    if (val.indexOf(' ') < 0) {
-      return ChangeQueryBuilder.FIELD_STARREDBY + ":" + val;
-    } else {
-      return ChangeQueryBuilder.FIELD_STARREDBY + ":\"" + val + "\"";
-    }
+    return ChangeQueryBuilder.FIELD_STARREDBY + ":" + accountId;
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OutputStreamQuery.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OutputStreamQuery.java
index b07b7f2..8f1e48f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OutputStreamQuery.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OutputStreamQuery.java
@@ -35,7 +35,6 @@
 import com.google.gson.Gson;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
-import com.google.inject.Provider;
 
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.RevWalk;
@@ -69,11 +68,11 @@
   private static final DateTimeFormatter dtf =
       DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss zzz");
 
-  public static enum OutputFormat {
+  public enum OutputFormat {
     TEXT, JSON
   }
 
-  private final Provider<ReviewDb> db;
+  private final ReviewDb db;
   private final GitRepositoryManager repoManager;
   private final ChangeQueryBuilder queryBuilder;
   private final QueryProcessor queryProcessor;
@@ -97,7 +96,7 @@
 
   @Inject
   OutputStreamQuery(
-      Provider<ReviewDb> db,
+      ReviewDb db,
       GitRepositoryManager repoManager,
       ChangeQueryBuilder queryBuilder,
       QueryProcessor queryProcessor,
@@ -239,7 +238,7 @@
     ChangeControl cc = d.changeControl().forUser(user);
 
     LabelTypes labelTypes = cc.getLabelTypes();
-    ChangeAttribute c = eventFactory.asChangeAttribute(db.get(), d.change());
+    ChangeAttribute c = eventFactory.asChangeAttribute(db, d.change());
     eventFactory.extend(c, d.change());
 
     if (!trackingFooters.isEmpty()) {
@@ -248,7 +247,7 @@
     }
 
     if (includeAllReviewers) {
-      eventFactory.addAllReviewers(db.get(), c, d.notes());
+      eventFactory.addAllReviewers(db, c, d.notes());
     }
 
     if (includeSubmitRecords) {
@@ -276,7 +275,7 @@
     }
 
     if (includePatchSets) {
-      eventFactory.addPatchSets(db.get(), rw, c, d.patchSets(),
+      eventFactory.addPatchSets(db, rw, c, d.patchSets(),
           includeApprovals ? d.approvals().asMap() : null,
           includeFiles, d.change(), labelTypes);
     }
@@ -285,7 +284,7 @@
       PatchSet current = d.currentPatchSet();
       if (current != null) {
         c.currentPatchSet =
-            eventFactory.asPatchSetAttribute(db.get(), rw, d.change(), current);
+            eventFactory.asPatchSetAttribute(db, rw, d.change(), current);
         eventFactory.addApprovals(c.currentPatchSet,
             d.currentApprovals(), labelTypes);
 
@@ -303,7 +302,7 @@
     if (includeComments) {
       eventFactory.addComments(c, d.messages());
       if (includePatchSets) {
-        eventFactory.addPatchSets(db.get(), rw, c, d.patchSets(),
+        eventFactory.addPatchSets(db, rw, c, d.patchSets(),
             includeApprovals ? d.approvals().asMap() : null,
             includeFiles, d.change(), labelTypes);
         for (PatchSetAttribute attribute : c.patchSets) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/DataSourceProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/DataSourceProvider.java
index 0c3bf67..b362a2e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/DataSourceProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/DataSourceProvider.java
@@ -91,7 +91,7 @@
     }
   }
 
-  public static enum Context {
+  public enum Context {
     SINGLE_USER, MULTI_USER
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/HANA.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/HANA.java
index ed4b9ba..523c336 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/HANA.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/HANA.java
@@ -30,7 +30,7 @@
   private Config cfg;
 
   @Inject
-  public HANA(@GerritServerConfig final Config cfg) {
+  HANA(@GerritServerConfig final Config cfg) {
     super("com.sap.db.jdbc.Driver");
     this.cfg = cfg;
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/MaxDb.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/MaxDb.java
index 7ef88f0..88908bb 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/MaxDb.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/MaxDb.java
@@ -29,7 +29,7 @@
   private Config cfg;
 
   @Inject
-  public MaxDb(@GerritServerConfig final Config cfg) {
+  MaxDb(@GerritServerConfig final Config cfg) {
     super("com.sap.dbtech.jdbc.DriverSapDB");
     this.cfg = cfg;
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/MySql.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/MySql.java
index 308cec8..20e1620 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/MySql.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/MySql.java
@@ -28,7 +28,7 @@
   private Config cfg;
 
   @Inject
-  public MySql(@GerritServerConfig final Config cfg) {
+  MySql(@GerritServerConfig final Config cfg) {
     super("com.mysql.jdbc.Driver");
     this.cfg = cfg;
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/PostgreSQL.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/PostgreSQL.java
index c58d0c2..e9ffae5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/PostgreSQL.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/PostgreSQL.java
@@ -30,7 +30,7 @@
   private Config cfg;
 
   @Inject
-  public PostgreSQL(@GerritServerConfig final Config cfg) {
+  PostgreSQL(@GerritServerConfig final Config cfg) {
     super("org.postgresql.Driver");
     this.cfg = cfg;
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaModule.java
index 2d4b65f..f23dabf 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaModule.java
@@ -19,7 +19,6 @@
 import com.google.gerrit.extensions.config.FactoryModule;
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.GerritPersonIdentProvider;
-import com.google.gerrit.server.api.config.GerritServerIdProvider;
 import com.google.gerrit.server.config.AllProjectsName;
 import com.google.gerrit.server.config.AllProjectsNameProvider;
 import com.google.gerrit.server.config.AllUsersName;
@@ -27,6 +26,7 @@
 import com.google.gerrit.server.config.AnonymousCowardName;
 import com.google.gerrit.server.config.AnonymousCowardNameProvider;
 import com.google.gerrit.server.config.GerritServerId;
+import com.google.gerrit.server.config.GerritServerIdProvider;
 
 import org.eclipse.jgit.lib.PersonIdent;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersion.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersion.java
index 8ddc86d..5ca31d0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersion.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersion.java
@@ -32,7 +32,7 @@
 /** A version of the database schema. */
 public abstract class SchemaVersion {
   /** The current schema version. */
-  public static final Class<Schema_121> C = Schema_121.class;
+  public static final Class<Schema_123> C = Schema_123.class;
 
   public static int getBinaryVersion() {
     return guessVersion(C);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_115.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_115.java
index 122b369..26cd3e1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_115.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_115.java
@@ -154,7 +154,7 @@
         RevWalk rw = new RevWalk(git)) {
       BatchRefUpdate bru = git.getRefDatabase().newBatchUpdate();
       for (Map.Entry<Account.Id, DiffPreferencesInfo> e : imports.entrySet()) {
-        try(MetaDataUpdate md = new MetaDataUpdate(GitReferenceUpdated.DISABLED,
+        try (MetaDataUpdate md = new MetaDataUpdate(GitReferenceUpdated.DISABLED,
             allUsersName, git, bru)) {
           md.getCommitBuilder().setAuthor(serverUser);
           md.getCommitBuilder().setCommitter(serverUser);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_119.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_119.java
index 4f6620e..ffa80a2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_119.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_119.java
@@ -149,7 +149,7 @@
       BatchRefUpdate bru = git.getRefDatabase().newBatchUpdate();
       for (Map.Entry<Account.Id, GeneralPreferencesInfo> e
           : imports.entrySet()) {
-        try(MetaDataUpdate md = new MetaDataUpdate(GitReferenceUpdated.DISABLED,
+        try (MetaDataUpdate md = new MetaDataUpdate(GitReferenceUpdated.DISABLED,
             allUsersName, git, bru)) {
           md.getCommitBuilder().setAuthor(serverUser);
           md.getCommitBuilder().setCommitter(serverUser);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_120.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_120.java
index fd94108..6179a06 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_120.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_120.java
@@ -55,7 +55,7 @@
     try (Repository git = mgr.openRepository(subbranch.getParentKey());
         RevWalk rw = new RevWalk(git)) {
       BatchRefUpdate bru = git.getRefDatabase().newBatchUpdate();
-      try(MetaDataUpdate md = new MetaDataUpdate(GitReferenceUpdated.DISABLED,
+      try (MetaDataUpdate md = new MetaDataUpdate(GitReferenceUpdated.DISABLED,
           subbranch.getParentKey(), git, bru)) {
         md.setMessage("Added superproject subscription during upgrade");
         ProjectConfig pc = ProjectConfig.read(md);
diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrettyFactory.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_122.java
similarity index 63%
rename from gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrettyFactory.java
rename to gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_122.java
index f68b629..b5b799d 100644
--- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrettyFactory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_122.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2010 The Android Open Source Project
+// Copyright (C) 2016 The Android Open Source Project
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -12,9 +12,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.prettify.client;
+package com.google.gerrit.server.schema;
 
-/** Creates a new PrettyFormatter instance for one formatting run. */
-public interface PrettyFactory {
-  PrettyFormatter get();
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+public class Schema_122 extends SchemaVersion {
+  @Inject
+  Schema_122(Provider<Schema_121> prior) {
+    super(prior);
+  }
+
+  // Adds tag column
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_123.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_123.java
new file mode 100644
index 0000000..d698974
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_123.java
@@ -0,0 +1,92 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.schema;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.RefNames;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.StarredChangesUtil;
+import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gwtorm.jdbc.JdbcSchema;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+import org.eclipse.jgit.lib.BatchRefUpdate;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.TextProgressMonitor;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.ReceiveCommand;
+
+import java.io.IOException;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Map;
+
+public class Schema_123 extends SchemaVersion {
+  private final GitRepositoryManager repoManager;
+  private final AllUsersName allUsersName;
+
+  @Inject
+  Schema_123(Provider<Schema_122> prior,
+      GitRepositoryManager repoManager,
+      AllUsersName allUsersName) {
+    super(prior);
+    this.repoManager = repoManager;
+    this.allUsersName = allUsersName;
+  }
+
+  @Override
+  protected void migrateData(ReviewDb db, UpdateUI ui)
+      throws OrmException, SQLException {
+    Multimap<Account.Id, Change.Id> imports = ArrayListMultimap.create();
+    try (Statement stmt = ((JdbcSchema) db).getConnection().createStatement();
+      ResultSet rs = stmt.executeQuery(
+          "SELECT "
+          + "account_id, "
+          + "change_id "
+          + "FROM starred_changes")) {
+      while (rs.next()) {
+        Account.Id accountId = new Account.Id(rs.getInt(1));
+        Change.Id changeId = new Change.Id(rs.getInt(2));
+        imports.put(accountId, changeId);
+      }
+    }
+
+    if (imports.isEmpty()) {
+      return;
+    }
+
+    try (Repository git = repoManager.openRepository(allUsersName);
+        RevWalk rw = new RevWalk(git)) {
+      BatchRefUpdate bru = git.getRefDatabase().newBatchUpdate();
+      ObjectId id = StarredChangesUtil.writeLabels(git,
+          StarredChangesUtil.DEFAULT_LABELS);
+      for (Map.Entry<Account.Id, Change.Id> e : imports.entries()) {
+        bru.addCommand(new ReceiveCommand(ObjectId.zeroId(), id,
+            RefNames.refsStarredChanges(e.getValue(), e.getKey())));
+      }
+      bru.execute(rw, new TextProgressMonitor());
+    } catch (IOException ex) {
+      throw new OrmException(ex);
+    }
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/tools/ToolsCatalog.java b/gerrit-server/src/main/java/com/google/gerrit/server/tools/ToolsCatalog.java
index f59bba9..37383b7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/tools/ToolsCatalog.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/tools/ToolsCatalog.java
@@ -135,7 +135,7 @@
 
   /** A file served out of the tools root directory. */
   public static class Entry {
-    public static enum Type {
+    public enum Type {
       DIR, FILE
     }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/util/HostPlatform.java b/gerrit-server/src/main/java/com/google/gerrit/server/util/HostPlatform.java
index c585270..86b3b7364 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/util/HostPlatform.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/util/HostPlatform.java
@@ -21,11 +21,11 @@
   private static final boolean win32 = computeWin32();
 
   /** @return true if this JVM is running on a Windows platform. */
-  public static final boolean isWin32() {
+  public static boolean isWin32() {
     return win32;
   }
 
-  private static final boolean computeWin32() {
+  private static boolean computeWin32() {
     final String osDotName =
         AccessController.doPrivileged(new PrivilegedAction<String>() {
           @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/util/MostSpecificComparator.java b/gerrit-server/src/main/java/com/google/gerrit/server/util/MostSpecificComparator.java
index 1cb180b..ce7f24d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/util/MostSpecificComparator.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/util/MostSpecificComparator.java
@@ -67,7 +67,7 @@
         cmp = -1;
       } else if (!p1_finite && p2_finite) {
         cmp = 1;
-      } else /* if (f1 == f2) */{
+      } else /* if (f1 == f2) */ {
         cmp = 0;
       }
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/util/TreeFormatter.java b/gerrit-server/src/main/java/com/google/gerrit/server/util/TreeFormatter.java
index cd559ee..883f972 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/util/TreeFormatter.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/util/TreeFormatter.java
@@ -19,7 +19,7 @@
 
 public class TreeFormatter {
 
-  public static interface TreeNode {
+  public interface TreeNode {
     String getDisplayName();
     boolean isVisible();
     SortedSet<? extends TreeNode> getChildren();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/validators/OutgoingEmailValidationListener.java b/gerrit-server/src/main/java/com/google/gerrit/server/validators/OutgoingEmailValidationListener.java
index 398a303..b2899c1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/validators/OutgoingEmailValidationListener.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/validators/OutgoingEmailValidationListener.java
@@ -29,7 +29,7 @@
   /**
    * Arguments supplied to validateOutgoingEmail.
    */
-  public static class Args {
+  class Args {
     // in arguments
     public String messageClass;
 
diff --git a/gerrit-server/src/main/java/gerrit/PRED_commit_stats_3.java b/gerrit-server/src/main/java/gerrit/PRED_commit_stats_3.java
index 4f665ee..1dbdb68 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_commit_stats_3.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_commit_stats_3.java
@@ -48,13 +48,13 @@
     Term a3 = arg3.dereference();
 
     PatchList pl = StoredValues.PATCH_LIST.get(engine);
-    if(!a1.unify(new IntegerTerm(pl.getPatches().size() -1),engine.trail)) { //Account for /COMMIT_MSG.
+    if (!a1.unify(new IntegerTerm(pl.getPatches().size() - 1),engine.trail)) { //Account for /COMMIT_MSG.
       return engine.fail();
     }
-    if(!a2.unify(new IntegerTerm(pl.getInsertions()),engine.trail)) {
+    if (!a2.unify(new IntegerTerm(pl.getInsertions()),engine.trail)) {
       return engine.fail();
     }
-    if(!a3.unify(new IntegerTerm(pl.getDeletions()),engine.trail)) {
+    if (!a3.unify(new IntegerTerm(pl.getDeletions()),engine.trail)) {
       return engine.fail();
     }
     return cont;
diff --git a/gerrit-server/src/main/resources/com/google/gerrit/server/tools/root/hooks/commit-msg b/gerrit-server/src/main/resources/com/google/gerrit/server/tools/root/hooks/commit-msg
index 937a623..8b85f9b 100644
--- a/gerrit-server/src/main/resources/com/google/gerrit/server/tools/root/hooks/commit-msg
+++ b/gerrit-server/src/main/resources/com/google/gerrit/server/tools/root/hooks/commit-msg
@@ -19,7 +19,7 @@
 
 unset GREP_OPTIONS
 
-CHANGE_ID_AFTER="Bug|Issue|Test|Feature"
+CHANGE_ID_AFTER="Bug|Issue|Test|Feature|Fixes|Fixed"
 MSG="$1"
 
 # Check for, and add if missing, a unique Change-Id
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/IdentifiedUserTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/IdentifiedUserTest.java
index 6349be2..390a4c1 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/IdentifiedUserTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/IdentifiedUserTest.java
@@ -60,7 +60,7 @@
   private static final String[] TEST_CASES = {
     "",
     "FirstName.LastName@Corporation.com",
-    "!#$%&'+-/=.?^`{|}~@[IPv6:0123:4567:89AB:CDEF:0123:4567:89AB:CDEF]"
+    "!#$%&'+-/=.?^`{|}~@[IPv6:0123:4567:89AB:CDEF:0123:4567:89AB:CDEF]",
   };
 
   @Before
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/StringUtilTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/StringUtilTest.java
index b4d6e96..0646eef0 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/StringUtilTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/StringUtilTest.java
@@ -51,7 +51,7 @@
         "string with 'quotes'", "string with 'quotes'",
         "C:\\Program Files\\MyProgram", "C:\\\\Program Files\\\\MyProgram",
         "string\nwith\nnewlines", "string\\nwith\\nnewlines",
-        "string\twith\ttabs", "string\\twith\\ttabs" };
+        "string\twith\ttabs", "string\\twith\\ttabs", };
     for (int i = 0; i < testPairs.length; i += 2) {
       assertEquals(StringUtil.escapeString(testPairs[i]), testPairs[i + 1]);
     }
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/config/GitwebConfigTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/config/GitwebConfigTest.java
index b03a381..12e563f 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/config/GitwebConfigTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/config/GitwebConfigTest.java
@@ -26,14 +26,14 @@
 
   @Test
   public void testValidPathSeparator() {
-    for(char c : VALID_CHARACTERS.toCharArray()) {
+    for (char c : VALID_CHARACTERS.toCharArray()) {
       assertTrue("valid character rejected: " + c, GitwebConfig.isValidPathSeparator(c));
     }
   }
 
   @Test
   public void testInalidPathSeparator() {
-    for(char c : SOME_INVALID_CHARACTERS.toCharArray()) {
+    for (char c : SOME_INVALID_CHARACTERS.toCharArray()) {
       assertFalse("invalid character accepted: " + c, GitwebConfig.isValidPathSeparator(c));
     }
   }
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/config/RepositoryConfigTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/config/RepositoryConfigTest.java
index b64bd1a..bf36738 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/config/RepositoryConfigTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/config/RepositoryConfigTest.java
@@ -16,7 +16,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import com.google.common.collect.Lists;
+import com.google.common.collect.ImmutableList;
 import com.google.gerrit.extensions.client.SubmitType;
 import com.google.gerrit.reviewdb.client.Project.NameKey;
 
@@ -26,7 +26,6 @@
 
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.util.Arrays;
 import java.util.List;
 
 public class RepositoryConfigTest {
@@ -98,48 +97,46 @@
 
   @Test
   public void testOwnerGroupsWhenNotConfigured() {
-    assertThat(repoCfg.getOwnerGroups(new NameKey("someProject"))).isEqualTo(
-        new String[] {});
+    assertThat(repoCfg.getOwnerGroups(new NameKey("someProject"))).isEmpty();
   }
 
   @Test
   public void testOwnerGroupsForStarFilter() {
-    String[] ownerGroups = new String[] {"group1", "group2"};
-    configureOwnerGroups("*", Lists.newArrayList(ownerGroups));
-    assertThat(repoCfg.getOwnerGroups(new NameKey("someProject"))).isEqualTo(
-        ownerGroups);
+    ImmutableList<String> ownerGroups = ImmutableList.of("group1", "group2");
+    configureOwnerGroups("*", ownerGroups);
+    assertThat(repoCfg.getOwnerGroups(new NameKey("someProject")))
+        .containsExactlyElementsIn(ownerGroups);
   }
 
   @Test
   public void testOwnerGroupsForSpecificFilter() {
-    String[] ownerGroups = new String[] {"group1", "group2"};
-    configureOwnerGroups("someProject", Lists.newArrayList(ownerGroups));
+    ImmutableList<String> ownerGroups = ImmutableList.of("group1", "group2");
+    configureOwnerGroups("someProject", ownerGroups);
     assertThat(repoCfg.getOwnerGroups(new NameKey("someOtherProject")))
-        .isEqualTo(new String[] {});
-    assertThat(repoCfg.getOwnerGroups(new NameKey("someProject"))).isEqualTo(
-        ownerGroups);
+        .isEmpty();
+    assertThat(repoCfg.getOwnerGroups(new NameKey("someProject")))
+        .containsExactlyElementsIn(ownerGroups);
   }
 
   @Test
   public void testOwnerGroupsForStartWithFilter() {
-    String[] ownerGroups1 = new String[] {"group1"};
-    String[] ownerGroups2 = new String[] {"group2"};
-    String[] ownerGroups3 = new String[] {"group3"};
+    ImmutableList<String> ownerGroups1 = ImmutableList.of("group1");
+    ImmutableList<String> ownerGroups2 = ImmutableList.of("group2");
+    ImmutableList<String> ownerGroups3 = ImmutableList.of("group3");
 
-    configureOwnerGroups("*", Lists.newArrayList(ownerGroups1));
-    configureOwnerGroups("somePath/*", Lists.newArrayList(ownerGroups2));
-    configureOwnerGroups("somePath/somePath/*",
-        Lists.newArrayList(ownerGroups3));
+    configureOwnerGroups("*", ownerGroups1);
+    configureOwnerGroups("somePath/*", ownerGroups2);
+    configureOwnerGroups("somePath/somePath/*", ownerGroups3);
 
-    assertThat(repoCfg.getOwnerGroups(new NameKey("someProject"))).isEqualTo(
-        ownerGroups1);
+    assertThat(repoCfg.getOwnerGroups(new NameKey("someProject")))
+        .containsExactlyElementsIn(ownerGroups1);
 
     assertThat(repoCfg.getOwnerGroups(new NameKey("somePath/someProject")))
-        .isEqualTo(ownerGroups2);
+        .containsExactlyElementsIn(ownerGroups2);
 
     assertThat(
         repoCfg.getOwnerGroups(new NameKey("somePath/somePath/someProject")))
-        .isEqualTo(ownerGroups3);
+        .containsExactlyElementsIn(ownerGroups3);
   }
 
   private void configureOwnerGroups(String projectFilter,
@@ -196,8 +193,10 @@
 
   @Test
   public void testAllBasePath() {
-    List<Path> allBasePaths = Arrays.asList(Paths.get("/someBasePath1"),
-        Paths.get("/someBasePath2"), Paths.get("/someBasePath2"));
+    ImmutableList<Path> allBasePaths = ImmutableList.of(
+        Paths.get("/someBasePath1"),
+        Paths.get("/someBasePath2"),
+        Paths.get("/someBasePath2"));
 
     configureBasePath("*", allBasePaths.get(0).toString());
     configureBasePath("project/*", allBasePaths.get(1).toString());
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/git/LabelNormalizerTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/git/LabelNormalizerTest.java
index 4f22a1c..6b6528e 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/git/LabelNormalizerTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/git/LabelNormalizerTest.java
@@ -214,7 +214,7 @@
   }
 
   private void save(ProjectConfig pc) throws Exception {
-    try(MetaDataUpdate md =
+    try (MetaDataUpdate md =
         metaDataUpdateFactory.create(pc.getProject().getNameKey(), user)) {
       pc.commit(md);
       projectCache.evict(pc.getProject().getNameKey());
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java
index 3f122e2..86fa0db 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java
@@ -18,7 +18,6 @@
 
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.config.SitePaths;
-import com.google.gerrit.server.notedb.NotesMigration;
 import com.google.gerrit.testutil.TempFileUtil;
 import com.google.gwtorm.client.KeyUtil;
 import com.google.gwtorm.server.StandardKeyEncoder;
@@ -53,16 +52,13 @@
     site.resolve("git").toFile().mkdir();
     cfg = new Config();
     cfg.setString("gerrit", null, "basePath", "git");
-    repoManager =
-        new LocalDiskRepositoryManager(site, cfg,
-            createNiceMock(NotesMigration.class));
+    repoManager = new LocalDiskRepositoryManager(site, cfg);
     repoManager.start();
   }
 
   @Test(expected = IllegalStateException.class)
   public void testThatNullBasePathThrowsAnException() {
-    new LocalDiskRepositoryManager(site, new Config(),
-        createNiceMock(NotesMigration.class));
+    new LocalDiskRepositoryManager(site, new Config());
   }
 
   @Test
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/git/MultiBaseLocalDiskRepositoryManagerTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/git/MultiBaseLocalDiskRepositoryManagerTest.java
index 4769b34..b26a228 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/git/MultiBaseLocalDiskRepositoryManagerTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/git/MultiBaseLocalDiskRepositoryManagerTest.java
@@ -23,7 +23,6 @@
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.config.RepositoryConfig;
 import com.google.gerrit.server.config.SitePaths;
-import com.google.gerrit.server.notedb.NotesMigration;
 import com.google.gerrit.testutil.TempFileUtil;
 import com.google.gwtorm.client.KeyUtil;
 import com.google.gwtorm.server.StandardKeyEncoder;
@@ -66,11 +65,8 @@
     configMock = createNiceMock(RepositoryConfig.class);
     expect(configMock.getAllBasePaths()).andReturn(new ArrayList<Path>()).anyTimes();
     replay(configMock);
-    NotesMigration notesMigrationMock = createNiceMock(NotesMigration.class);
-    replay(notesMigrationMock);
     repoManager =
-        new MultiBaseLocalDiskRepositoryManager(site, cfg,
-            notesMigrationMock, configMock);
+        new MultiBaseLocalDiskRepositoryManager(site, cfg, configMock);
   }
 
   @After
@@ -188,7 +184,6 @@
         .andReturn(Arrays.asList(Paths.get("repos"))).anyTimes();
     replay(configMock);
     repoManager =
-        new MultiBaseLocalDiskRepositoryManager(site, cfg,
-            createNiceMock(NotesMigration.class), configMock);
+        new MultiBaseLocalDiskRepositoryManager(site, cfg, configMock);
   }
 }
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/ioutil/BasicSerializationTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/ioutil/BasicSerializationTest.java
index dbc8f02..f6bdeac 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/ioutil/BasicSerializationTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/ioutil/BasicSerializationTest.java
@@ -156,6 +156,6 @@
 
   private static byte[] b(int a, int b, int c, int d, int e, int f, int g, int h) {
     return new byte[] {(byte) a, (byte) b, (byte) c, (byte) d, //
-        (byte) e, (byte) f, (byte) g, (byte) h};
+        (byte) e, (byte) f, (byte) g, (byte) h,};
   }
 }
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/ioutil/ColumnFormatterTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/ioutil/ColumnFormatterTest.java
index fa4ac0e..049e17d 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/ioutil/ColumnFormatterTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/ioutil/ColumnFormatterTest.java
@@ -29,7 +29,7 @@
     private PrintWriter printWriter;
     private StringWriter stringWriter;
 
-    public PrintWriterComparator() {
+    PrintWriterComparator() {
       stringWriter = new StringWriter();
       printWriter = new PrintWriter(stringWriter);
     }
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/AbstractChangeNotesTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/AbstractChangeNotesTest.java
index ac4bf71..5a11bfa 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/AbstractChangeNotesTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/AbstractChangeNotesTest.java
@@ -207,6 +207,7 @@
   protected ChangeUpdate newUpdate(Change c, CurrentUser user)
       throws Exception {
     ChangeUpdate update = TestChanges.newUpdate(injector, c, user);
+    update.setPatchSetId(c.currentPatchSetId());
     update.setAllowWriteToNewRef(true);
     return update;
   }
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeBundleTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeBundleTest.java
index fd20852..c4f5e19 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeBundleTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeBundleTest.java
@@ -135,7 +135,7 @@
 
     c2.setTopic("topic");
     assertDiffs(b1, b2,
-        "topic differs for Change.Id "+ c1.getId() + ": {null} != {topic}");
+        "topic differs for Change.Id " + c1.getId() + ": {null} != {topic}");
   }
 
   @Test
@@ -280,14 +280,14 @@
     assertDiffs(b1, b2,
         "Differing numbers of ChangeMessages for Change.Id " + id + ":\n"
         + "ChangeMessage{key=" + id + ",uuid1, author=100,"
-        + " writtenOn=2009-09-30 17:00:06.0, patchset=" + id + ",1,"
+        + " writtenOn=2009-09-30 17:00:06.0, patchset=" + id + ",1, tag=null,"
         + " message=[message 2]}\n"
         + "ChangeMessage{key=" + id + ",uuid2, author=100,"
-        + " writtenOn=2009-09-30 17:00:12.0, patchset=" + id + ",1,"
+        + " writtenOn=2009-09-30 17:00:12.0, patchset=" + id + ",1, tag=null,"
         + " message=[null]}\n"
         + "--- vs. ---\n"
         + "ChangeMessage{key=" + id + ",uuid1, author=100,"
-        + " writtenOn=2009-09-30 17:00:06.0, patchset=" + id + ",1,"
+        + " writtenOn=2009-09-30 17:00:06.0, patchset=" + id + ",1, tag=null,"
         + " message=[message 2]}");
   }
 
@@ -356,6 +356,45 @@
   }
 
   @Test
+  public void diffChangeMessagesAllowsNullPatchSetIdFromReviewDb()
+      throws Exception {
+    Change c = TestChanges.newChange(project, accountId);
+    int id = c.getId().get();
+    ChangeMessage cm1 = new ChangeMessage(
+        new ChangeMessage.Key(c.getId(), "uuid"),
+        accountId, TimeUtil.nowTs(), c.currentPatchSetId());
+    cm1.setMessage("message 1");
+    ChangeMessage cm2 = clone(cm1);
+    cm2.setPatchSetId(null);
+
+    ChangeBundle b1 = new ChangeBundle(c, messages(cm1), patchSets(),
+        approvals(), comments(), REVIEW_DB);
+    ChangeBundle b2 = new ChangeBundle(c, messages(cm2), patchSets(),
+        approvals(), comments(), REVIEW_DB);
+
+    // Both are ReviewDb, exact patch set ID match is required.
+    assertDiffs(b1, b2,
+        "patchset differs for ChangeMessage.Key " + c.getId() + ",uuid:"
+            + " {" + id + ",1} != {null}");
+
+    // Null patch set ID on ReviewDb is ignored.
+    b1 = new ChangeBundle(c, messages(cm1), patchSets(), approvals(),
+        comments(), NOTE_DB);
+    b2 = new ChangeBundle(c, messages(cm2), patchSets(), approvals(),
+        comments(), REVIEW_DB);
+    assertNoDiffs(b1, b2);
+
+    // Null patch set ID on NoteDb is not ignored (but is not realistic).
+    b1 = new ChangeBundle(c, messages(cm1), patchSets(), approvals(),
+        comments(), REVIEW_DB);
+    b2 = new ChangeBundle(c, messages(cm2), patchSets(), approvals(),
+        comments(), NOTE_DB);
+    assertDiffs(b1, b2,
+        "patchset differs for ChangeMessage on " + id + " at index 0:"
+            + " {" + id + ",1} != {null}");
+  }
+
+  @Test
   public void diffPatchSetIdSets() throws Exception {
     Change c = TestChanges.newChange(project, accountId);
     TestChanges.incrementPatchSet(c);
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeNotesParserTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeNotesParserTest.java
index 2968a62..dc00eaa 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeNotesParserTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeNotesParserTest.java
@@ -414,6 +414,32 @@
     assertParseFails(writeCommit(msg, serverIdent));
   }
 
+  @Test
+  public void parseTag() throws Exception {
+    assertParseSucceeds("Update change\n"
+        + "\n"
+        + "Patch-Set: 1\n"
+        + "Branch: refs/heads/master\n"
+        + "Change-id: I577fb248e474018276351785930358ec0450e9f7\n"
+        + "Subject: Change subject\n"
+        + "Tag:\n");
+    assertParseSucceeds("Update change\n"
+        + "\n"
+        + "Patch-Set: 1\n"
+        + "Branch: refs/heads/master\n"
+        + "Change-id: I577fb248e474018276351785930358ec0450e9f7\n"
+        + "Subject: Change subject\n"
+        + "Tag: jenkins\n");
+    assertParseFails("Update change\n"
+        + "\n"
+        + "Patch-Set: 1\n"
+        + "Branch: refs/heads/master\n"
+        + "Change-id: I577fb248e474018276351785930358ec0450e9f7\n"
+        + "Subject: Change subject\n"
+        + "Tag: ci\n"
+        + "Tag: jenkins\n");
+  }
+
   private RevCommit writeCommit(String body) throws Exception {
     return writeCommit(body, noteUtil.newIdent(
         changeOwner.getAccount(), TimeUtil.nowTs(), serverIdent,
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeNotesTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeNotesTest.java
index 8cca245..ad2f50a 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeNotesTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/ChangeNotesTest.java
@@ -15,6 +15,8 @@
 package com.google.gerrit.server.notedb;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.reviewdb.client.RefNames.refsDraftComments;
+import static com.google.gerrit.server.notedb.ChangeNoteUtil.changeRefName;
 import static com.google.gerrit.server.notedb.ReviewerStateInternal.CC;
 import static com.google.gerrit.server.notedb.ReviewerStateInternal.REVIEWER;
 import static com.google.gerrit.testutil.TestChanges.incrementPatchSet;
@@ -43,7 +45,6 @@
 import com.google.gerrit.reviewdb.client.PatchLineComment.Status;
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.client.PatchSetApproval;
-import com.google.gerrit.reviewdb.client.RefNames;
 import com.google.gerrit.reviewdb.client.RevId;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
@@ -69,6 +70,117 @@
   private DraftCommentNotes.Factory draftNotesFactory;
 
   @Test
+  public void tagChangeMessage() throws Exception {
+    String tag = "jenkins";
+    Change c = newChange();
+    ChangeUpdate update = newUpdate(c, changeOwner);
+    update.setChangeMessage("verification from jenkins");
+    update.setTag(tag);
+    update.commit();
+
+    ChangeNotes notes = newNotes(c);
+
+    assertThat(notes.getChangeMessages()).hasSize(1);
+    assertThat(notes.getChangeMessages().get(0).getTag()).isEqualTo(tag);
+  }
+
+  @Test
+  public void tagInlineCommenrts() throws Exception {
+    String tag = "jenkins";
+    Change c = newChange();
+    RevCommit commit = tr.commit().message("PS2").create();
+    ChangeUpdate update = newUpdate(c, changeOwner);
+    update.putComment(newPublishedComment(c.currentPatchSetId(), "a.txt",
+        "uuid1", new CommentRange(1, 2, 3, 4), 1, changeOwner, null,
+        TimeUtil.nowTs(), "Comment", (short) 1, commit.name()));
+    update.setTag(tag);
+    update.commit();
+
+    ChangeNotes notes = newNotes(c);
+
+    ImmutableListMultimap<RevId, PatchLineComment> comments = notes.getComments();
+    assertThat(comments).hasSize(1);
+    assertThat(
+        comments.entries().asList().get(0).getValue().getTag())
+            .isEqualTo(tag);
+  }
+
+  @Test
+  public void tagApprovals() throws Exception {
+    String tag1 = "jenkins";
+    String tag2 = "ip";
+    Change c = newChange();
+    ChangeUpdate update = newUpdate(c, changeOwner);
+    update.putApproval("Verified", (short) -1);
+    update.setTag(tag1);
+    update.commit();
+
+    update = newUpdate(c, changeOwner);
+    update.putApproval("Verified", (short) 1);
+    update.setTag(tag2);
+    update.commit();
+
+    ChangeNotes notes = newNotes(c);
+
+    ImmutableListMultimap<PatchSet.Id, PatchSetApproval> approvals =
+        notes.getApprovals();
+    assertThat(approvals).hasSize(2);
+    assertThat(approvals.entries().asList().get(0).getValue().getTag())
+        .isEqualTo(tag1);
+    assertThat(approvals.entries().asList().get(1).getValue().getTag())
+        .isEqualTo(tag2);
+  }
+
+  @Test
+  public void multipleTags() throws Exception {
+    String ipTag = "ip";
+    String coverageTag = "coverage";
+    String integrationTag = "integration";
+    Change c = newChange();
+
+    ChangeUpdate update = newUpdate(c, changeOwner);
+    update.putApproval("Verified", (short) -1);
+    update.setChangeMessage("integration verification");
+    update.setTag(integrationTag);
+    update.commit();
+
+    RevCommit commit = tr.commit().message("PS2").create();
+    update = newUpdate(c, changeOwner);
+    update.putComment(newPublishedComment(c.currentPatchSetId(), "a.txt",
+        "uuid1", new CommentRange(1, 2, 3, 4), 1, changeOwner, null,
+        TimeUtil.nowTs(), "Comment", (short) 1, commit.name()));
+    update.setChangeMessage("coverage verification");
+    update.setTag(coverageTag);
+    update.commit();
+
+    update = newUpdate(c, changeOwner);
+    update.setChangeMessage("ip clear");
+    update.setTag(ipTag);
+    update.commit();
+
+    ChangeNotes notes = newNotes(c);
+
+    ImmutableListMultimap<PatchSet.Id, PatchSetApproval> approvals =
+        notes.getApprovals();
+    assertThat(approvals).hasSize(1);
+    PatchSetApproval approval = approvals.entries().asList().get(0).getValue();
+    assertThat(approval.getTag()).isEqualTo(integrationTag);
+    assertThat(approval.getValue()).isEqualTo(-1);
+
+    ImmutableListMultimap<RevId, PatchLineComment> comments =
+        notes.getComments();
+    assertThat(comments).hasSize(1);
+    assertThat(comments.entries().asList().get(0).getValue().getTag())
+        .isEqualTo(coverageTag);
+
+    ImmutableList<ChangeMessage> messages = notes.getChangeMessages();
+    assertThat(messages).hasSize(3);
+    assertThat(messages.get(0).getTag()).isEqualTo(integrationTag);
+    assertThat(messages.get(1).getTag()).isEqualTo(coverageTag);
+    assertThat(messages.get(2).getTag()).isEqualTo(ipTag);
+  }
+
+  @Test
   public void approvalsOnePatchSet() throws Exception {
     Change c = newChange();
     ChangeUpdate update = newUpdate(c, changeOwner);
@@ -413,7 +525,7 @@
   @Test
   public void emptyChangeUpdate() throws Exception {
     Change c = newChange();
-    Ref initial = repo.exactRef(ChangeNoteUtil.changeRefName(c.getId()));
+    Ref initial = repo.exactRef(changeRefName(c.getId()));
     assertThat(initial).isNotNull();
 
     // Empty update doesn't create a new commit.
@@ -421,7 +533,7 @@
     update.commit();
     assertThat(update.getResult()).isNull();
 
-    Ref updated = repo.exactRef(ChangeNoteUtil.changeRefName(c.getId()));
+    Ref updated = repo.exactRef(changeRefName(c.getId()));
     assertThat(updated.getObjectId()).isEqualTo(initial.getObjectId());
   }
 
@@ -1625,6 +1737,62 @@
   }
 
   @Test
+  public void addingPublishedCommentDoesNotCreateNoOpCommitOnEmptyDraftRef()
+      throws Exception {
+    Change c = newChange();
+    String uuid = "uuid";
+    String rev = "abcd4567abcd4567abcd4567abcd4567abcd4567";
+    CommentRange range = new CommentRange(1, 1, 2, 1);
+    PatchSet.Id ps1 = c.currentPatchSetId();
+    String filename = "filename1";
+    short side = (short) 1;
+
+    ChangeUpdate update = newUpdate(c, otherUser);
+    Timestamp now = TimeUtil.nowTs();
+    PatchLineComment comment = newComment(ps1, filename, uuid, range,
+        range.getEndLine(), otherUser, null, now, "comment on ps1", side,
+        rev, Status.PUBLISHED);
+    update.putComment(comment);
+    update.commit();
+
+    assertThat(repo.exactRef(changeRefName(c.getId()))).isNotNull();
+    String draftRef = refsDraftComments(otherUser.getAccountId(), c.getId());
+    assertThat(exactRefAllUsers(draftRef)).isNull();
+  }
+
+  @Test
+  public void addingPublishedCommentDoesNotCreateNoOpCommitOnNonEmptyDraftRef()
+      throws Exception {
+    Change c = newChange();
+    String rev = "abcd4567abcd4567abcd4567abcd4567abcd4567";
+    CommentRange range = new CommentRange(1, 1, 2, 1);
+    PatchSet.Id ps1 = c.currentPatchSetId();
+    String filename = "filename1";
+    short side = (short) 1;
+
+    ChangeUpdate update = newUpdate(c, otherUser);
+    Timestamp now = TimeUtil.nowTs();
+    PatchLineComment draft = newComment(ps1, filename, "uuid1", range,
+        range.getEndLine(), otherUser, null, now, "draft comment on ps1", side,
+        rev, Status.DRAFT);
+    update.putComment(draft);
+    update.commit();
+
+    String draftRef = refsDraftComments(otherUser.getAccountId(), c.getId());
+    ObjectId old = exactRefAllUsers(draftRef);
+    assertThat(old).isNotNull();
+
+    update = newUpdate(c, otherUser);
+    PatchLineComment pub = newComment(ps1, filename, "uuid2", range,
+        range.getEndLine(), otherUser, null, now, "comment on ps1", side,
+        rev, Status.PUBLISHED);
+    update.putComment(pub);
+    update.commit();
+
+    assertThat(exactRefAllUsers(draftRef)).isEqualTo(old);
+  }
+
+  @Test
   public void fileComment() throws Exception {
     Change c = newChange();
     ChangeUpdate update = newUpdate(c, otherUser);
@@ -1760,7 +1928,7 @@
     assertThat(msg.getAuthor()).isNull();
 
     update = newUpdate(c, internalUser);
-    exception.expect(UnsupportedOperationException.class);
+    exception.expect(IllegalStateException.class);
     update.putApproval("Code-Review", (short) 1);
   }
 
@@ -1784,8 +1952,7 @@
     update.putComment(comment2);
     update.commit();
 
-
-    String refName = RefNames.refsDraftComments(otherUserId, c.getId());
+    String refName = refsDraftComments(otherUserId, c.getId());
     ObjectId oldDraftId = exactRefAllUsers(refName);
 
     update = newUpdate(c, otherUser);
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/CommitMessageOutputTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/CommitMessageOutputTest.java
index 907db6b..47c8a03 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/CommitMessageOutputTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/CommitMessageOutputTest.java
@@ -272,6 +272,23 @@
         update.getResult());
   }
 
+  @Test
+  public void changeMessageWithTag() throws Exception {
+    Change c = newChange();
+    ChangeUpdate update = newUpdate(c, changeOwner);
+    update.setChangeMessage("Change message with tag");
+    update.setTag("jenkins");
+    update.commit();
+
+    assertBodyEquals("Update patch set 1\n"
+        + "\n"
+        + "Change message with tag\n"
+        + "\n"
+        + "Patch-set: 1\n"
+        + "Tag: jenkins\n",
+        update.getResult());
+  }
+
   private RevCommit parseCommit(ObjectId id) throws Exception {
     if (id instanceof RevCommit) {
       return (RevCommit) id;
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/NoteDbChangeStateTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/NoteDbChangeStateTest.java
index 915f94a..216f71b 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/NoteDbChangeStateTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/NoteDbChangeStateTest.java
@@ -149,7 +149,7 @@
     checkArgument(args.length % 2 == 0);
     ImmutableMap.Builder<Account.Id, ObjectId> b = ImmutableMap.builder();
     for (int i = 0; i < args.length / 2; i++) {
-      b.put((Account.Id) args[2*i], (ObjectId) args[2*i+1]);
+      b.put((Account.Id) args[2 * i], (ObjectId) args[2 * i + 1]);
     }
     return b.build();
   }
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/RepoSequenceTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/RepoSequenceTest.java
index b726e2d..9c265a8 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/notedb/RepoSequenceTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/notedb/RepoSequenceTest.java
@@ -160,7 +160,7 @@
 
   @Test
   public void failOnWrongType() throws Exception {
-    try (Repository repo = repoManager.openMetadataRepository(project)) {
+    try (Repository repo = repoManager.openRepository(project)) {
       TestRepository<Repository> tr = new TestRepository<>(repo);
       tr.branch(RefNames.REFS_SEQUENCES + "id").commit().create();
       try {
@@ -206,7 +206,7 @@
 
   private ObjectId writeBlob(String sequenceName, String value) {
     String refName = RefNames.REFS_SEQUENCES + sequenceName;
-    try (Repository repo = repoManager.openMetadataRepository(project);
+    try (Repository repo = repoManager.openRepository(project);
         ObjectInserter ins = repo.newObjectInserter()) {
       ObjectId newId = ins.insert(OBJ_BLOB, value.getBytes(UTF_8));
       ins.flush();
@@ -222,7 +222,7 @@
 
   private String readBlob(String sequenceName) throws Exception {
     String refName = RefNames.REFS_SEQUENCES + sequenceName;
-    try (Repository repo = repoManager.openMetadataRepository(project);
+    try (Repository repo = repoManager.openRepository(project);
         RevWalk rw = new RevWalk(repo)) {
       ObjectId id = repo.exactRef(refName).getObjectId();
       return new String(rw.getObjectReader().open(id).getCachedBytes(), UTF_8);
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
index 129c155..6e2f9c9 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
@@ -1173,6 +1173,23 @@
   }
 
   @Test
+  public void byStarredBy() throws Exception {
+    TestRepository<Repo> repo = createProject("repo");
+    Change change1 = insert(repo, newChange(repo));
+    Change change2 = insert(repo, newChange(repo));
+    insert(repo, newChange(repo));
+
+    gApi.accounts().self().starChange(change1.getId().toString());
+    gApi.accounts().self().starChange(change2.getId().toString());
+
+    int user2 = accountManager.authenticate(AuthRequest.forUser("anotheruser"))
+        .getAccountId().get();
+
+    assertQuery("starredby:self", change2, change1);
+    assertQuery("starredby:" + user2);
+  }
+
+  @Test
   public void byFrom() throws Exception {
     TestRepository<Repo> repo = createProject("repo");
     Change change1 = insert(repo, newChange(repo));
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/util/SubmoduleSectionParserTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/util/SubmoduleSectionParserTest.java
index 3945da7..0ea74a5 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/util/SubmoduleSectionParserTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/util/SubmoduleSectionParserTest.java
@@ -268,7 +268,7 @@
     private final String path;
     private final String branch;
 
-    public SubmoduleSection(final String url, final String path,
+    SubmoduleSection(final String url, final String path,
         final String branch) {
       this.url = url;
       this.path = path;
diff --git a/gerrit-server/src/test/java/com/google/gerrit/testutil/DisabledReviewDb.java b/gerrit-server/src/test/java/com/google/gerrit/testutil/DisabledReviewDb.java
index fa7a5c4..01465a2 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/testutil/DisabledReviewDb.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/testutil/DisabledReviewDb.java
@@ -32,7 +32,6 @@
 import com.google.gerrit.reviewdb.server.PatchSetApprovalAccess;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.reviewdb.server.SchemaVersionAccess;
-import com.google.gerrit.reviewdb.server.StarredChangeAccess;
 import com.google.gerrit.reviewdb.server.SystemConfigAccess;
 import com.google.gwtorm.server.Access;
 import com.google.gwtorm.server.StatementExecutor;
@@ -123,11 +122,6 @@
   }
 
   @Override
-  public StarredChangeAccess starredChanges() {
-    throw new Disabled();
-  }
-
-  @Override
   public AccountProjectWatchAccess accountProjectWatches() {
     throw new Disabled();
   }
diff --git a/gerrit-server/src/test/java/com/google/gerrit/testutil/FilesystemLoggingMockingTestCase.java b/gerrit-server/src/test/java/com/google/gerrit/testutil/FilesystemLoggingMockingTestCase.java
index 7f8fc32..eee3a8d 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/testutil/FilesystemLoggingMockingTestCase.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/testutil/FilesystemLoggingMockingTestCase.java
@@ -118,7 +118,7 @@
    * @throws IOException If a file could not be created.
    */
   private File createTempFile(String suffix) throws IOException {
-    String prefix ="gerrit_test_";
+    String prefix = "gerrit_test_";
     if (!Strings.isNullOrEmpty(getName())) {
       prefix += getName() + "_";
     }
diff --git a/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryRepositoryManager.java b/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryRepositoryManager.java
index 656185d..b8fa592 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryRepositoryManager.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryRepositoryManager.java
@@ -89,12 +89,6 @@
   }
 
   @Override
-  public synchronized Repo openMetadataRepository(
-      Project.NameKey name) throws RepositoryNotFoundException {
-    return openRepository(name);
-  }
-
-  @Override
   public synchronized SortedSet<Project.NameKey> list() {
     SortedSet<Project.NameKey> names = Sets.newTreeSet();
     for (DfsRepository repo : repos.values()) {
diff --git a/gerrit-server/src/test/java/com/google/gerrit/testutil/LoggingMockingTestCase.java b/gerrit-server/src/test/java/com/google/gerrit/testutil/LoggingMockingTestCase.java
index 218fa0a..770dfcd 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/testutil/LoggingMockingTestCase.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/testutil/LoggingMockingTestCase.java
@@ -109,7 +109,7 @@
     // and we can improve later to allow tests to specify which loggers are
     // to check.
     loggerName = this.getClass().getCanonicalName();
-    loggerName = loggerName.substring(0, loggerName.length()-4);
+    loggerName = loggerName.substring(0, loggerName.length() - 4);
     loggerSettings = LogUtil.logToCollection(loggerName, loggedEvents);
   }
 
diff --git a/gerrit-server/src/test/java/com/google/gerrit/testutil/NoteDbChecker.java b/gerrit-server/src/test/java/com/google/gerrit/testutil/NoteDbChecker.java
index 95101ab..6fc5ef9 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/testutil/NoteDbChecker.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/testutil/NoteDbChecker.java
@@ -117,7 +117,7 @@
 
   public void assertNoChangeRef(Project.NameKey project, Change.Id changeId)
       throws Exception {
-    try (Repository repo = repoManager.openMetadataRepository(project)) {
+    try (Repository repo = repoManager.openRepository(project)) {
       assertThat(repo.exactRef(ChangeNoteUtil.changeRefName(changeId)))
           .isNull();
     }
diff --git a/gerrit-server/src/test/java/com/google/gerrit/testutil/TestChanges.java b/gerrit-server/src/test/java/com/google/gerrit/testutil/TestChanges.java
index 7ac6cbe..84d9b6c 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/testutil/TestChanges.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/testutil/TestChanges.java
@@ -101,7 +101,7 @@
                 user),
             TimeUtil.nowTs(), Ordering.<String> natural());
 
-    ChangeNotes notes = update.getChangeNotes();
+    ChangeNotes notes = update.getNotes();
     boolean hasPatchSets = notes.getPatchSets() != null
         && !notes.getPatchSets().isEmpty();
     NotesMigration migration = injector.getInstance(NotesMigration.class);
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/AliasCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/AliasCommand.java
index efdfae9..c4727f5 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/AliasCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/AliasCommand.java
@@ -20,7 +20,6 @@
 import com.google.gerrit.extensions.annotations.RequiresCapability;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.account.CapabilityControl;
-import com.google.inject.Provider;
 
 import org.apache.sshd.server.Command;
 import org.apache.sshd.server.Environment;
@@ -33,12 +32,12 @@
 /** Command that executes some other command. */
 public class AliasCommand extends BaseCommand {
   private final DispatchCommandProvider root;
-  private final Provider<CurrentUser> currentUser;
+  private final CurrentUser currentUser;
   private final CommandName command;
   private final AtomicReference<Command> atomicCmd;
 
   AliasCommand(@CommandName(Commands.ROOT) DispatchCommandProvider root,
-      Provider<CurrentUser> currentUser, CommandName command) {
+      CurrentUser currentUser, CommandName command) {
     this.root = root;
     this.currentUser = currentUser;
     this.command = command;
@@ -99,7 +98,8 @@
       try {
         cmd.destroy();
       } catch (Exception e) {
-        Throwables.propagate(e);
+        Throwables.propagateIfPossible(e);
+        throw new RuntimeException(e);
       }
     }
   }
@@ -107,12 +107,11 @@
   private void checkRequiresCapability(Command cmd) throws UnloggedFailure {
     RequiresCapability rc = cmd.getClass().getAnnotation(RequiresCapability.class);
     if (rc != null) {
-      CurrentUser user = currentUser.get();
-      CapabilityControl ctl = user.getCapabilities();
+      CapabilityControl ctl = currentUser.getCapabilities();
       if (!ctl.canPerform(rc.value()) && !ctl.canAdministrateServer()) {
         String msg = String.format(
             "fatal: %s does not have \"%s\" capability.",
-            user.getUserName(), rc.value());
+            currentUser.getUserName(), rc.value());
         throw new UnloggedFailure(BaseCommand.STATUS_NOT_ADMIN, msg);
       }
     }
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/AliasCommandProvider.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/AliasCommandProvider.java
index ee28e03..432844c 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/AliasCommandProvider.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/AliasCommandProvider.java
@@ -29,7 +29,7 @@
   private DispatchCommandProvider root;
 
   @Inject
-  private Provider<CurrentUser> currentUser;
+  private CurrentUser currentUser;
 
   public AliasCommandProvider(CommandName command) {
     this.command = command;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java
index ec49f5c..f296ef3 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java
@@ -33,7 +33,6 @@
 import com.google.gerrit.util.cli.CmdLineParser;
 import com.google.gerrit.util.cli.EndOfOptionsHandler;
 import com.google.inject.Inject;
-import com.google.inject.Provider;
 
 import org.apache.sshd.common.SshException;
 import org.apache.sshd.server.Command;
@@ -89,10 +88,10 @@
   private WorkQueue.Executor executor;
 
   @Inject
-  private Provider<CurrentUser> user;
+  private CurrentUser user;
 
   @Inject
-  private Provider<SshScope.Context> contextProvider;
+  private SshScope.Context context;
 
   /** Commands declared by a plugin can be scoped by the plugin name. */
   @Inject(optional = true)
@@ -278,7 +277,7 @@
     final TaskThunk tt = new TaskThunk(thunk);
 
     if (isAdminHighPriorityCommand()
-        && user.get().getCapabilities().canAdministrateServer()) {
+        && user.getCapabilities().canAdministrateServer()) {
       // Admin commands should not block the main work threads (there
       // might be an interactive shell there), nor should they wait
       // for the main work threads.
@@ -289,7 +288,7 @@
     }
   }
 
-  private final boolean isAdminHighPriorityCommand() {
+  private boolean isAdminHighPriorityCommand() {
     return getClass().getAnnotation(AdminHighPriorityCommand.class) != null;
   }
 
@@ -332,8 +331,8 @@
     if (!(e instanceof UnloggedFailure)) {
       final StringBuilder m = new StringBuilder();
       m.append("Internal server error");
-      if (user.get().isIdentifiedUser()) {
-        final IdentifiedUser u = user.get().asIdentifiedUser();
+      if (user.isIdentifiedUser()) {
+        final IdentifiedUser u = user.asIdentifiedUser();
         m.append(" (user ");
         m.append(u.getAccount().getUserName());
         m.append(" account ");
@@ -341,7 +340,7 @@
         m.append(")");
       }
       m.append(" during ");
-      m.append(contextProvider.get().getCommandLine());
+      m.append(context.getCommandLine());
       log.error(m.toString(), e);
     }
 
@@ -388,18 +387,16 @@
 
   private final class TaskThunk implements CancelableRunnable, ProjectRunnable {
     private final CommandRunnable thunk;
-    private final Context context;
     private final String taskName;
     private Project.NameKey projectName;
 
     private TaskThunk(final CommandRunnable thunk) {
       this.thunk = thunk;
-      this.context = contextProvider.get();
 
       StringBuilder m = new StringBuilder();
       m.append(context.getCommandLine());
-      if (user.get().isIdentifiedUser()) {
-        IdentifiedUser u = user.get().asIdentifiedUser();
+      if (user.isIdentifiedUser()) {
+        IdentifiedUser u = user.asIdentifiedUser();
         m.append(" (").append(u.getAccount().getUserName()).append(")");
       }
       this.taskName = m.toString();
@@ -488,12 +485,12 @@
   }
 
   /** Runnable function which can throw an exception. */
-  public static interface CommandRunnable {
+  public interface CommandRunnable {
     void run() throws Exception;
   }
 
   /** Runnable function which can retrieve a project name related to the task */
-  public static interface ProjectCommandRunnable extends CommandRunnable {
+  public interface ProjectCommandRunnable extends CommandRunnable {
     // execute parser command before running, in order to be able to retrieve
     // project name
     void executeParseCommand() throws Exception;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandMetaData.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandMetaData.java
index 7fb9226..5b8f5fa 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandMetaData.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandMetaData.java
@@ -27,7 +27,7 @@
 @Target({ElementType.TYPE})
 @Retention(RUNTIME)
 public @interface CommandMetaData {
-  public enum Mode {
+  enum Mode {
     MASTER, MASTER_OR_SLAVE;
     public boolean isSupported(boolean slaveMode) {
       return this == MASTER_OR_SLAVE || !slaveMode;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DispatchCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DispatchCommand.java
index 3890f1c..8873be9 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DispatchCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DispatchCommand.java
@@ -23,7 +23,6 @@
 import com.google.gerrit.server.account.CapabilityUtils;
 import com.google.gerrit.server.args4j.SubcommandHandler;
 import com.google.inject.Inject;
-import com.google.inject.Provider;
 import com.google.inject.assistedinject.Assisted;
 
 import org.apache.sshd.server.Command;
@@ -45,7 +44,7 @@
     DispatchCommand create(Map<String, CommandProvider> map);
   }
 
-  private final Provider<CurrentUser> currentUser;
+  private final CurrentUser currentUser;
   private final Map<String, CommandProvider> commands;
   private final AtomicReference<Command> atomicCmd;
 
@@ -56,7 +55,7 @@
   private List<String> args = new ArrayList<>();
 
   @Inject
-  DispatchCommand(final Provider<CurrentUser> cu,
+  DispatchCommand(CurrentUser cu,
       @Assisted final Map<String, CommandProvider> all) {
     currentUser = cu;
     commands = all;
@@ -137,7 +136,8 @@
       try {
         cmd.destroy();
       } catch (Exception e) {
-        Throwables.propagate(e);
+        Throwables.propagateIfPossible(e);
+        throw new RuntimeException(e);
       }
     }
   }
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java
index 0e33a50..5fd8932 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java
@@ -140,7 +140,7 @@
   private static final Logger sshDaemonLog =
       LoggerFactory.getLogger(SshDaemon.class);
 
-  public static enum SshSessionBackend {
+  public enum SshSessionBackend {
     MINA,
     NIO2
   }
@@ -489,21 +489,21 @@
         do {
           bits = next(31);
           val = bits % n;
-        } while (bits - val + (n-1) < 0);
+        } while (bits - val + (n - 1) < 0);
         return val;
       }
       throw new IllegalArgumentException();
     }
 
     protected final int next(int numBits) {
-      int bytes = (numBits+7)/8;
+      int bytes = (numBits + 7) / 8;
       byte[] next = new byte[bytes];
       int ret = 0;
       random.nextBytes(next);
       for (int i = 0; i < bytes; i++) {
         ret = (next[i] & 0xFF) | (ret << 8);
       }
-      return ret >>> (bytes*8 - numBits);
+      return ret >>> (bytes * 8 - numBits);
     }
   }
 
@@ -674,7 +674,7 @@
         try {
           kerberosPrincipal = "host/" +
               InetAddress.getLocalHost().getCanonicalHostName();
-        } catch(UnknownHostException e) {
+        } catch (UnknownHostException e) {
           kerberosPrincipal = "host/localhost";
         }
       }
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SuExec.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SuExec.java
index 26ad50f..4308db9 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SuExec.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SuExec.java
@@ -25,7 +25,6 @@
 import com.google.gerrit.server.config.AuthConfig;
 import com.google.gerrit.sshd.SshScope.Context;
 import com.google.inject.Inject;
-import com.google.inject.Provider;
 
 import org.apache.sshd.server.Command;
 import org.apache.sshd.server.Environment;
@@ -50,8 +49,8 @@
   private final DispatchCommandProvider dispatcher;
 
   private boolean enableRunAs;
-  private Provider<CurrentUser> caller;
-  private Provider<SshSession> session;
+  private CurrentUser caller;
+  private SshSession session;
   private IdentifiedUser.GenericFactory userFactory;
   private SshScope.Context callingContext;
 
@@ -69,7 +68,8 @@
   @Inject
   SuExec(final SshScope sshScope,
       @CommandName(Commands.ROOT) final DispatchCommandProvider dispatcher,
-      final Provider<CurrentUser> caller, final Provider<SshSession> session,
+      final CurrentUser caller,
+      final SshSession session,
       final IdentifiedUser.GenericFactory userFactory,
       final SshScope.Context callingContext,
       AuthConfig config) {
@@ -112,12 +112,12 @@
   }
 
   private void checkCanRunAs() throws UnloggedFailure {
-    if (caller.get() instanceof PeerDaemonUser) {
+    if (caller instanceof PeerDaemonUser) {
       // OK.
     } else if (!enableRunAs) {
       throw new UnloggedFailure(1,
           "fatal: suexec disabled by auth.enableRunAs = false");
-    } else if (!caller.get().getCapabilities().canRunAs()) {
+    } else if (!caller.getCapabilities().canRunAs()) {
       throw new UnloggedFailure(1, "fatal: suexec not permitted");
     }
   }
@@ -125,16 +125,15 @@
   private SshSession newSession() {
     final SocketAddress peer;
     if (peerAddress == null) {
-      peer = session.get().getRemoteAddress();
+      peer = session.getRemoteAddress();
     } else {
       peer = peerAddress;
     }
-    CurrentUser self = caller.get();
-    if (self instanceof PeerDaemonUser) {
-      self = null;
+    if (caller instanceof PeerDaemonUser) {
+      caller = null;
     }
-    return new SshSession(session.get(), peer,
-        userFactory.runAs(peer, accountId, self));
+    return new SshSession(session, peer,
+        userFactory.runAs(peer, accountId, caller));
   }
 
   private static String join(List<String> args) {
@@ -155,7 +154,8 @@
       try {
         cmd.destroy();
       } catch (Exception e) {
-        Throwables.propagate(e);
+        Throwables.propagateIfPossible(e);
+        throw new RuntimeException(e);
       }
     }
   }
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminSetParent.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminSetParent.java
index 2fb91f6..5f6bb05 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminSetParent.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminSetParent.java
@@ -33,7 +33,6 @@
 import com.google.gerrit.sshd.CommandMetaData;
 import com.google.gerrit.sshd.SshCommand;
 import com.google.inject.Inject;
-import com.google.inject.Provider;
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
@@ -79,9 +78,9 @@
   private AllProjectsName allProjectsName;
 
   @Inject
-  private Provider<ListChildProjects> listChildProjects;
+  private ListChildProjects listChildProjects;
 
-  private Project.NameKey newParentKey = null;
+  private Project.NameKey newParentKey;
 
   @Override
   protected void run() throws Failure {
@@ -187,7 +186,7 @@
     if (newParentKey != null) {
       automaticallyExcluded.addAll(getAllParents(newParentKey));
     }
-    for (final ProjectInfo child : listChildProjects.get().apply(
+    for (final ProjectInfo child : listChildProjects.apply(
         new ProjectResource(parent))) {
       final Project.NameKey childName = new Project.NameKey(child.name);
       if (!excluded.contains(childName)) {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ApproveOption.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ApproveOption.java
index 59892a3..fb961d8 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ApproveOption.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ApproveOption.java
@@ -123,6 +123,7 @@
   public static class Handler extends OneArgumentOptionHandler<Short> {
     private final ApproveOption cmdOption;
 
+    // CS IGNORE RedundantModifier FOR NEXT 1 LINES. REASON: needed by org.kohsuke.args4j.Option
     public Handler(final CmdLineParser parser, final OptionDef option,
         final Setter<Short> setter) {
       super(parser, option, setter);
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AproposCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AproposCommand.java
index 0aa12c4..cc393ce 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AproposCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AproposCommand.java
@@ -36,7 +36,7 @@
   @Inject
   @CanonicalWebUrl String url;
 
-  @Argument(index=0, required = true, metaVar = "QUERY")
+  @Argument(index = 0, required = true, metaVar = "QUERY")
   private String q;
 
   @Override
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/FlushCaches.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/FlushCaches.java
index 2bcd4cf..fcf365c 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/FlushCaches.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/FlushCaches.java
@@ -29,7 +29,6 @@
 import com.google.gerrit.sshd.CommandMetaData;
 import com.google.gerrit.sshd.SshCommand;
 import com.google.inject.Inject;
-import com.google.inject.Provider;
 
 import org.kohsuke.args4j.Option;
 
@@ -51,7 +50,7 @@
   private boolean list;
 
   @Inject
-  private Provider<ListCaches> listCaches;
+  private ListCaches listCaches;
 
   @Inject
   private PostCaches postCaches;
@@ -94,7 +93,7 @@
 
   @SuppressWarnings("unchecked")
   private void doList() {
-    for (String name : (List<String>) listCaches.get()
+    for (String name : (List<String>) listCaches
         .setFormat(OutputFormat.LIST).apply(new ConfigResource())) {
       stderr.print(name);
       stderr.print('\n');
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListGroupsCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListGroupsCommand.java
index 75072e8..bd97286 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListGroupsCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListGroupsCommand.java
@@ -72,7 +72,7 @@
         final GroupControl.GenericFactory genericGroupControlFactory,
         final Provider<IdentifiedUser> identifiedUser,
         final IdentifiedUser.GenericFactory userFactory,
-        final Provider<GetGroups> accountGetGroups,
+        final GetGroups accountGetGroups,
         final GroupJson json,
         GroupBackend groupBackend) {
       super(groupCache, groupControlFactory, genericGroupControlFactory,
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/QueryShell.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/QueryShell.java
index 0529b90..4c930c8 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/QueryShell.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/QueryShell.java
@@ -51,7 +51,7 @@
     QueryShell create(@Assisted InputStream in, @Assisted OutputStream out);
   }
 
-  public static enum OutputFormat {
+  public enum OutputFormat {
     PRETTY, JSON, JSON_SINGLE
   }
 
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java
index 00cf53f..a9b6d3f 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java
@@ -42,7 +42,6 @@
 import com.google.gson.JsonSyntaxException;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
-import com.google.inject.Provider;
 
 import org.kohsuke.args4j.Argument;
 import org.kohsuke.args4j.Option;
@@ -124,6 +123,9 @@
       + "specified can be applied to the given patch set(s)")
   private boolean strictLabels;
 
+  @Option(name = "--tag", aliases = "-t", usage = "applies a tag to the given review", metaVar = "TAG")
+  private String changeTag;
+
   @Option(name = "--label", aliases = "-l", usage = "custom label(s) to assign", metaVar = "LABEL=VALUE")
   void addLabel(final String token) {
     LabelVote v = LabelVote.parseWithEquals(token);
@@ -138,7 +140,7 @@
   private AllProjectsName allProjects;
 
   @Inject
-  private Provider<GerritApi> gApi;
+  private GerritApi gApi;
 
   @Inject
   private PatchSetParser psParser;
@@ -198,6 +200,9 @@
       if (rebaseChange) {
         throw error("json and rebase actions are mutually exclusive");
       }
+      if (changeTag != null) {
+        throw error("json and tag actions are mutually exclusive");
+      }
     }
     if (rebaseChange) {
       if (deleteDraftPatchSet) {
@@ -245,7 +250,7 @@
 
   private void applyReview(PatchSet patchSet,
       final ReviewInput review) throws RestApiException {
-    gApi.get().changes()
+    gApi.changes()
         .id(patchSet.getId().getParentKey().get())
         .revision(patchSet.getRevision().get())
         .review(review);
@@ -268,6 +273,7 @@
 
     ReviewInput review = new ReviewInput();
     review.message = Strings.emptyToNull(changeComment);
+    review.tag = Strings.emptyToNull(changeTag);
     review.notify = notify;
     review.labels = Maps.newTreeMap();
     review.drafts = ReviewInput.DraftHandling.PUBLISH;
@@ -300,7 +306,7 @@
         applyReview(patchSet, review);
       }
 
-      if (rebaseChange){
+      if (rebaseChange) {
         revisionApi(patchSet).rebase();
       }
 
@@ -319,7 +325,7 @@
   }
 
   private ChangeApi changeApi(PatchSet patchSet) throws RestApiException {
-    return gApi.get().changes().id(patchSet.getId().getParentKey().get());
+    return gApi.changes().id(patchSet.getId().getParentKey().get());
   }
 
   private RevisionApi revisionApi(PatchSet patchSet) throws RestApiException {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ScpCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ScpCommand.java
index 194e65f9..5fc877c 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ScpCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ScpCommand.java
@@ -198,7 +198,7 @@
   private void header(final Entry dir, final int len) throws IOException,
       UnsupportedEncodingException {
     final StringBuilder buf = new StringBuilder();
-    switch(dir.getType()){
+    switch (dir.getType()) {
       case DIR:
         buf.append(TYPE_DIR);
         break;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetLoggingLevelCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetLoggingLevelCommand.java
index 49edf14..6277eb4 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetLoggingLevelCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetLoggingLevelCommand.java
@@ -40,7 +40,7 @@
   private static final String LOG_CONFIGURATION = "log4j.properties";
   private static final String JAVA_OPTIONS_LOG_CONFIG = "log4j.configuration";
 
-  private static enum LevelOption {
+  private enum LevelOption {
     ALL,
     TRACE,
     DEBUG,
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetMembersCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetMembersCommand.java
index 923865a..d1235cc 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetMembersCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetMembersCommand.java
@@ -34,7 +34,6 @@
 import com.google.gerrit.sshd.CommandMetaData;
 import com.google.gerrit.sshd.SshCommand;
 import com.google.inject.Inject;
-import com.google.inject.Provider;
 
 import org.kohsuke.args4j.Argument;
 import org.kohsuke.args4j.Option;
@@ -62,16 +61,16 @@
   private List<AccountGroup.UUID> groups = Lists.newArrayList();
 
   @Inject
-  private Provider<AddMembers> addMembers;
+  private AddMembers addMembers;
 
   @Inject
-  private Provider<DeleteMembers> deleteMembers;
+  private DeleteMembers deleteMembers;
 
   @Inject
-  private Provider<AddIncludedGroups> addIncludedGroups;
+  private AddIncludedGroups addIncludedGroups;
 
   @Inject
-  private Provider<DeleteIncludedGroups> deleteIncludedGroups;
+  private DeleteIncludedGroups deleteIncludedGroups;
 
   @Inject
   private GroupsCollection groupsCollection;
@@ -89,19 +88,19 @@
           groupsCollection.parse(TopLevelResource.INSTANCE,
               IdString.fromUrl(groupUuid.get()));
       if (!accountsToRemove.isEmpty()) {
-        deleteMembers.get().apply(resource, fromMembers(accountsToRemove));
+        deleteMembers.apply(resource, fromMembers(accountsToRemove));
         reportMembersAction("removed from", resource, accountsToRemove);
       }
       if (!groupsToRemove.isEmpty()) {
-        deleteIncludedGroups.get().apply(resource, fromGroups(groupsToRemove));
+        deleteIncludedGroups.apply(resource, fromGroups(groupsToRemove));
         reportGroupsAction("excluded from", resource, groupsToRemove);
       }
       if (!accountsToAdd.isEmpty()) {
-        addMembers.get().apply(resource, fromMembers(accountsToAdd));
+        addMembers.apply(resource, fromMembers(accountsToAdd));
         reportMembersAction("added to", resource, accountsToAdd);
       }
       if (!groupsToInclude.isEmpty()) {
-        addIncludedGroups.get().apply(resource, fromGroups(groupsToInclude));
+        addIncludedGroups.apply(resource, fromGroups(groupsToInclude));
         reportGroupsAction("included to", resource, groupsToInclude);
       }
     }
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetReviewersCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetReviewersCommand.java
index 0718dc6..63cb54f 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetReviewersCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetReviewersCommand.java
@@ -33,7 +33,6 @@
 import com.google.gerrit.sshd.SshCommand;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
-import com.google.inject.Provider;
 
 import org.kohsuke.args4j.Argument;
 import org.kohsuke.args4j.Option;
@@ -82,13 +81,13 @@
   private ReviewerResource.Factory reviewerFactory;
 
   @Inject
-  private Provider<PostReviewers> postReviewersProvider;
+  private PostReviewers postReviewers;
 
   @Inject
-  private Provider<DeleteReviewer> deleteReviewerProvider;
+  private DeleteReviewer deleteReviewer;
 
   @Inject
-  private Provider<CurrentUser> userProvider;
+  private CurrentUser currentUser;
 
   @Inject
   private ChangesCollection changesCollection;
@@ -123,12 +122,11 @@
 
     // Remove reviewers
     //
-    DeleteReviewer delete = deleteReviewerProvider.get();
     for (Account.Id reviewer : toRemove) {
       ReviewerResource rsrc = reviewerFactory.create(changeRsrc, reviewer);
       String error = null;
       try {
-        delete.apply(rsrc, new DeleteReviewer.Input());
+        deleteReviewer.apply(rsrc, new DeleteReviewer.Input());
       } catch (ResourceNotFoundException e) {
         error = String.format("could not remove %s: not found", reviewer);
       } catch (Exception e) {
@@ -143,14 +141,13 @@
 
     // Add reviewers
     //
-    PostReviewers post = postReviewersProvider.get();
     for (String reviewer : toAdd) {
       AddReviewerInput input = new AddReviewerInput();
       input.reviewer = reviewer;
       input.confirmed = true;
       String error;
       try {
-        error = post.apply(changeRsrc, input).error;
+        error = postReviewers.apply(changeRsrc, input).error;
       } catch (Exception e) {
         error = String.format("could not add %s: %s", reviewer, e.getMessage());
       }
@@ -164,8 +161,7 @@
   }
 
   private void addChangeImpl(String id) throws UnloggedFailure, OrmException {
-    List<ChangeControl> matched =
-        changeFinder.find(id, userProvider.get());
+    List<ChangeControl> matched = changeFinder.find(id, currentUser);
     List<ChangeControl> toAdd = new ArrayList<>(changes.size());
     for (ChangeControl ctl : matched) {
       if (!changes.containsKey(ctl.getId()) && inProject(ctl.getProject())
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowCaches.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowCaches.java
index b5801bf..3e0cec3 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowCaches.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowCaches.java
@@ -38,7 +38,6 @@
 import com.google.gerrit.sshd.SshCommand;
 import com.google.gerrit.sshd.SshDaemon;
 import com.google.inject.Inject;
-import com.google.inject.Provider;
 
 import org.apache.sshd.common.io.IoAcceptor;
 import org.apache.sshd.common.io.IoSession;
@@ -84,13 +83,13 @@
   private SshDaemon daemon;
 
   @Inject
-  private Provider<ListCaches> listCaches;
+  private ListCaches listCaches;
 
   @Inject
-  private Provider<GetSummary> getSummary;
+  private GetSummary getSummary;
 
   @Inject
-  private Provider<CurrentUser> self;
+  private CurrentUser self;
 
   @Option(name = "--width", aliases = {"-w"}, metaVar = "COLS", usage = "width of output table")
   private int columns = 80;
@@ -125,7 +124,7 @@
     stdout.print('\n');
 
     stdout.print(String.format(//
-        "%1s %-"+nw+"s|%-21s|  %-5s |%-9s|\n" //
+        "%1s %-" + nw + "s|%-21s|  %-5s |%-9s|\n" //
         , "" //
         , "Name" //
         , "Entries" //
@@ -133,7 +132,7 @@
         , "Hit Ratio" //
     ));
     stdout.print(String.format(//
-        "%1s %-"+nw+"s|%6s %6s %7s|  %-5s  |%-4s %-4s|\n" //
+        "%1s %-" + nw + "s|%6s %6s %7s|  %-5s  |%-4s %-4s|\n" //
         , "" //
         , "" //
         , "Mem" //
@@ -155,11 +154,11 @@
     printDiskCaches(caches);
     stdout.print('\n');
 
-    if (self.get().getCapabilities().canMaintainServer()) {
+    if (self.getCapabilities().canMaintainServer()) {
       sshSummary();
 
       SummaryInfo summary =
-          getSummary.get().setGc(gc).setJvm(showJVM).apply(new ConfigResource());
+          getSummary.setGc(gc).setJvm(showJVM).apply(new ConfigResource());
       taskSummary(summary.taskSummary);
       memSummary(summary.memSummary);
       threadSummary(summary.threadSummary);
@@ -175,7 +174,7 @@
   private Collection<CacheInfo> getCaches() {
     @SuppressWarnings("unchecked")
     Map<String, CacheInfo> caches =
-        (Map<String, CacheInfo>) listCaches.get().apply(new ConfigResource());
+        (Map<String, CacheInfo>) listCaches.apply(new ConfigResource());
     for (Map.Entry<String, CacheInfo> entry : caches.entrySet()) {
       CacheInfo cache = entry.getValue();
       cache.name = entry.getKey();
@@ -209,7 +208,7 @@
 
   private void printCache(CacheInfo cache) {
     stdout.print(String.format(
-        "%1s %-"+nw+"s|%6s %6s %7s| %7s |%4s %4s|\n",
+        "%1s %-" + nw + "s|%6s %6s %7s| %7s |%4s %4s|\n",
         CacheType.DISK.equals(cache.type) ? "D" : "",
         cache.name,
         nullToEmpty(cache.entries.mem),
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/StreamEvents.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/StreamEvents.java
index 29b7987..2da1b6d 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/StreamEvents.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/StreamEvents.java
@@ -81,8 +81,8 @@
 
   /** Special event to notify clients they missed other events. */
   private static final class DroppedOutputEvent extends Event {
-    private final static String TYPE = "dropped-output";
-    public DroppedOutputEvent() {
+    private static final String TYPE = "dropped-output";
+    DroppedOutputEvent() {
       super(TYPE);
     }
   }
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/TestSubmitRuleCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/TestSubmitRuleCommand.java
index 9c4a680..7e74ef0 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/TestSubmitRuleCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/TestSubmitRuleCommand.java
@@ -20,16 +20,15 @@
 import com.google.gerrit.server.change.TestSubmitRule;
 import com.google.gerrit.sshd.CommandMetaData;
 import com.google.inject.Inject;
-import com.google.inject.Provider;
 
 /** Command that allows testing of prolog submit-rules in a live instance. */
 @CommandMetaData(name = "rule", description = "Test prolog submit rules")
 final class TestSubmitRuleCommand extends BaseTestPrologCommand {
   @Inject
-  private Provider<TestSubmitRule> view;
+  private TestSubmitRule view;
 
   @Override
   protected RestModifyView<RevisionResource, TestSubmitRuleInput> createView() {
-    return view.get();
+    return view;
   }
 }
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/TestSubmitTypeCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/TestSubmitTypeCommand.java
index 34d4bdc..3a885f9 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/TestSubmitTypeCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/TestSubmitTypeCommand.java
@@ -21,15 +21,14 @@
 import com.google.gerrit.server.change.TestSubmitType;
 import com.google.gerrit.sshd.CommandMetaData;
 import com.google.inject.Inject;
-import com.google.inject.Provider;
 
 @CommandMetaData(name = "type", description = "Test prolog submit type")
 final class TestSubmitTypeCommand extends BaseTestPrologCommand {
   @Inject
-  private Provider<TestSubmitType> view;
+  private TestSubmitType view;
 
   @Override
   protected RestModifyView<RevisionResource, TestSubmitRuleInput> createView() {
-    return view.get();
+    return view;
   }
 }
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Upload.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Upload.java
index d278f4b..39efb26 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Upload.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Upload.java
@@ -27,7 +27,6 @@
 import com.google.gerrit.sshd.AbstractGitCommand;
 import com.google.gerrit.sshd.SshSession;
 import com.google.inject.Inject;
-import com.google.inject.Provider;
 
 import org.eclipse.jgit.transport.PreUploadHook;
 import org.eclipse.jgit.transport.PreUploadHookChain;
@@ -39,7 +38,7 @@
 /** Publishes Git repositories over SSH using the Git upload-pack protocol. */
 final class Upload extends AbstractGitCommand {
   @Inject
-  private Provider<ReviewDb> db;
+  private ReviewDb db;
 
   @Inject
   private TransferConfig config;
@@ -71,7 +70,7 @@
     final UploadPack up = new UploadPack(repo);
     if (!projectControl.allRefsAreVisible()) {
       up.setAdvertiseRefsHook(new VisibleRefFilter(tagCache, changeCache, repo,
-          projectControl, db.get(), true));
+          projectControl, db, true));
     }
     up.setPackConfig(config.getPackConfig());
     up.setTimeout(config.getTimeout());
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/UploadArchive.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/UploadArchive.java
index c3dae3a..8bfe4e1 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/UploadArchive.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/UploadArchive.java
@@ -23,7 +23,6 @@
 import com.google.gerrit.server.change.GetArchive;
 import com.google.gerrit.sshd.AbstractGitCommand;
 import com.google.inject.Inject;
-import com.google.inject.Provider;
 
 import org.eclipse.jgit.api.ArchiveCommand;
 import org.eclipse.jgit.api.errors.GitAPIException;
@@ -104,7 +103,7 @@
   @Inject
   private GetArchive.AllowedFormats allowedFormats;
   @Inject
-  private Provider<ReviewDb> db;
+  private ReviewDb db;
   private Options options = new Options();
 
   /**
@@ -127,7 +126,7 @@
         throw new Failure(1, "fatal: 'argument' token or flush expected");
       }
       String[] parts = s.substring(argCmd.length()).split("=", 2);
-      for(String p : parts) {
+      for (String p : parts) {
         args.add(p);
       }
     }
@@ -218,7 +217,7 @@
   private boolean canRead(ObjectId revId) throws IOException {
     try (RevWalk rw = new RevWalk(repo)) {
       RevCommit commit = rw.parseCommit(revId);
-      return projectControl.canReadCommit(db.get(), rw, commit);
+      return projectControl.canReadCommit(db, rw, commit);
     }
   }
 }
diff --git a/gerrit-war/src/main/java/com/google/gerrit/httpd/UnzippedDistribution.java b/gerrit-war/src/main/java/com/google/gerrit/httpd/UnzippedDistribution.java
index 665d420..fe4a864 100644
--- a/gerrit-war/src/main/java/com/google/gerrit/httpd/UnzippedDistribution.java
+++ b/gerrit-war/src/main/java/com/google/gerrit/httpd/UnzippedDistribution.java
@@ -36,7 +36,7 @@
   private ServletContext servletContext;
   private File pluginsDir;
 
-  public UnzippedDistribution(ServletContext servletContext) {
+  UnzippedDistribution(ServletContext servletContext) {
     this.servletContext = servletContext;
   }
 
diff --git a/lib/JGIT_VERSION b/lib/JGIT_VERSION
index 16db0c6..878d673 100644
--- a/lib/JGIT_VERSION
+++ b/lib/JGIT_VERSION
@@ -1,4 +1,4 @@
 include_defs('//lib/maven.defs')
 
-REPO = GERRIT # Leave here even if set to MAVEN_CENTRAL.
-VERS = '4.2.0.201601211800-r.136-g8efdaaf'
+REPO = MAVEN_CENTRAL # Leave here even if set to MAVEN_CENTRAL.
+VERS = '4.3.0.201604071810-r'
diff --git a/lib/asciidoctor/java/AsciiDoctor.java b/lib/asciidoctor/java/AsciiDoctor.java
index dce939d..4b9ba37 100644
--- a/lib/asciidoctor/java/AsciiDoctor.java
+++ b/lib/asciidoctor/java/AsciiDoctor.java
@@ -104,7 +104,7 @@
 
     for (String attribute : attributes) {
       int equalsIndex = attribute.indexOf('=');
-      if(equalsIndex > -1) {
+      if (equalsIndex > -1) {
         String name = attribute.substring(0, equalsIndex);
         String value = attribute.substring(equalsIndex + 1, attribute.length());
 
diff --git a/lib/codemirror/BUCK b/lib/codemirror/BUCK
index 2252eb92..30d29ae 100644
--- a/lib/codemirror/BUCK
+++ b/lib/codemirror/BUCK
@@ -1,14 +1,14 @@
 include_defs('//lib/maven.defs')
 include_defs('//lib/codemirror/cm.defs')
 
-VERSION = '5.13.2'
+VERSION = '5.13.4'
 TOP = 'META-INF/resources/webjars/codemirror/%s' % VERSION
 TOP_MINIFIED = 'META-INF/resources/webjars/codemirror-minified/%s' % VERSION
 
 maven_jar(
   name = 'codemirror-minified',
   id = 'org.webjars.npm:codemirror-minified:' + VERSION,
-  sha1 = '420b73c0dfa7885ff7f60df2dce7d2cbae4ffeef',
+  sha1 = 'fb207d777aad82423d098c3660bd2ca72775bf6e',
   attach_source = False,
   license = 'codemirror-minified',
   visibility = [],
@@ -17,7 +17,7 @@
 maven_jar(
   name = 'codemirror-original',
   id = 'org.webjars.npm:codemirror:' + VERSION,
-  sha1 = '4a26f060aeca679fdf751d2b480499c8a5f71e47',
+  sha1 = '4130b0a7e998d304277a86062351cb9e2840cbfa',
   attach_source = False,
   license = 'codemirror-original',
   visibility = [],
diff --git a/lib/codemirror/cm.defs b/lib/codemirror/cm.defs
index edd8dd6..a3db79fb 100644
--- a/lib/codemirror/cm.defs
+++ b/lib/codemirror/cm.defs
@@ -8,8 +8,9 @@
 CM_JS = [
   'lib/codemirror.js',
   'mode/meta.js',
-  'keymap/vim.js',
   'keymap/emacs.js',
+  'keymap/sublime.js',
+  'keymap/vim.js',
 ]
 
 CM_ADDONS = [
@@ -19,6 +20,7 @@
   'edit/trailingspace.js',
   'scroll/annotatescrollbar.js',
   'scroll/simplescrollbars.js',
+  'search/jump-to-line.js',
   'search/matchesonscrollbar.js',
   'search/searchcursor.js',
   'search/search.js',
diff --git a/lib/jgit/org.eclipse.jgit.archive/BUCK b/lib/jgit/org.eclipse.jgit.archive/BUCK
index 49b773c..99270e9 100644
--- a/lib/jgit/org.eclipse.jgit.archive/BUCK
+++ b/lib/jgit/org.eclipse.jgit.archive/BUCK
@@ -4,7 +4,7 @@
 maven_jar(
   name = 'jgit-archive',
   id = 'org.eclipse.jgit:org.eclipse.jgit.archive:' + VERS,
-  sha1 = '1b3a0cb7b8c2629e33902b3daf1067accca62eaf',
+  sha1 = 'c065b765aac56cdbe531634fdfd829a6ce8bbd0c',
   license = 'jgit',
   repository = REPO,
   deps = ['@jgit//org.eclipse.jgit:jgit'],
diff --git a/lib/jgit/org.eclipse.jgit.http.server/BUCK b/lib/jgit/org.eclipse.jgit.http.server/BUCK
index 6493dc2..aa33510 100644
--- a/lib/jgit/org.eclipse.jgit.http.server/BUCK
+++ b/lib/jgit/org.eclipse.jgit.http.server/BUCK
@@ -4,7 +4,7 @@
 maven_jar(
   name = 'jgit-servlet',
   id = 'org.eclipse.jgit:org.eclipse.jgit.http.server:' + VERS,
-  sha1 = 'b493401b9778cdc38f7c08f111c6385a434b2ac2',
+  sha1 = '516925ff0df67705e368c905a910ed982655cc32',
   license = 'jgit',
   repository = REPO,
   deps = ['@jgit//org.eclipse.jgit:jgit'],
diff --git a/lib/jgit/org.eclipse.jgit.junit/BUCK b/lib/jgit/org.eclipse.jgit.junit/BUCK
index 12eea2c..bcc583c 100644
--- a/lib/jgit/org.eclipse.jgit.junit/BUCK
+++ b/lib/jgit/org.eclipse.jgit.junit/BUCK
@@ -4,7 +4,7 @@
 maven_jar(
   name = 'junit',
   id = 'org.eclipse.jgit:org.eclipse.jgit.junit:' + VERS,
-  sha1 = 'c68ddb3e2aaca05b1d2f8250dd107b5f484ed603',
+  sha1 = '060a98c260b23f64c47e3fb4d77b684ccb64c114',
   license = 'DO_NOT_DISTRIBUTE',
   repository = REPO,
   unsign = True,
diff --git a/lib/jgit/org.eclipse.jgit/BUCK b/lib/jgit/org.eclipse.jgit/BUCK
index 17182d0..669e406 100644
--- a/lib/jgit/org.eclipse.jgit/BUCK
+++ b/lib/jgit/org.eclipse.jgit/BUCK
@@ -4,8 +4,8 @@
 maven_jar(
   name = 'jgit',
   id = 'org.eclipse.jgit:org.eclipse.jgit:' + VERS,
-  bin_sha1 = '32f50e3c0c4f53d8fdca147d3ff0b6ef0dc02eb0',
-  src_sha1 = '1ff155886d6ce2e6e566a90960862aa0e5b226d8',
+  bin_sha1 = 'e3c57967fb8df5172d62bb4bbbd355554db4c65d',
+  src_sha1 = '4d64b05a50d581a2884a5b7dc66163be18bac755',
   license = 'jgit',
   repository = REPO,
   unsign = True,
diff --git a/lib/js.defs b/lib/js.defs
index 570ed1e..e44ac44 100644
--- a/lib/js.defs
+++ b/lib/js.defs
@@ -144,7 +144,8 @@
   genrule(
     name = '%s__vulcanized' % name,
     cmd = ' '.join([
-      'unzip', '-qd', '$SRCDIR', '$(location %s)' % components,
+      'unzip', '-qd', '$TMP', '$(location %s)' % components,
+      '&&', 'ln', '-s', '-f', '$TMP/bower_components', '.',
       '&&', run_npm_binary('//lib/js:vulcanize')
     ] + VULCANIZE_FLAGS + extra_flags + [
       '--out-html', '$OUT',
diff --git a/lib/maven.defs b/lib/maven.defs
index 4107770..913be35 100644
--- a/lib/maven.defs
+++ b/lib/maven.defs
@@ -16,6 +16,7 @@
 GERRIT_API = 'GERRIT_API:'
 MAVEN_CENTRAL = 'MAVEN_CENTRAL:'
 MAVEN_LOCAL = 'MAVEN_LOCAL:'
+MAVEN_SNAPSHOT = 'MAVEN_SNAPSHOT:'
 
 def define_license(name):
   n = 'LICENSE-' + name
@@ -43,37 +44,48 @@
     local_license = False):
   from os import path
 
+  def maven_snapshot(parts):
+    if len(parts) != 4:
+      raise NameError('%s:\nexpected id="groupId:artifactId:version:snapshot]"'
+                      % id)
+    group, artifact, version, snapshot = parts
+    jar = path.join(name,
+      version + '-SNAPSHOT',
+      '-'.join([artifact.lower(), version, snapshot]))
+    url = '/'.join([
+      repository,
+      group.replace('.', '/'),
+      artifact,
+      version + '-SNAPSHOT',
+      '-'.join([artifact.lower(), version, snapshot])])
+    return jar, url
+
+  def maven_release(parts):
+    if len(parts) not in [3, 4]:
+      raise NameError('%s:\nexpected id="groupId:artifactId:version[:classifier]"'
+                      % id)
+    if len(parts) == 4:
+      group, artifact, version, classifier = parts
+      file_version = version + '-' + classifier
+    else:
+      group, artifact, version = parts
+      file_version = version
+
+    jar = path.join(name, artifact.lower() + '-' + file_version)
+    url = '/'.join([
+      repository,
+      group.replace('.', '/'),
+      artifact,
+      version,
+      artifact + '-' + file_version])
+
+    return jar, url
+
   parts = id.split(':')
-  if len(parts) not in [3, 4]:
-    raise NameError('%s:\nexpected id="groupId:artifactId:version[:classifier]"'
-                    % id)
-  if len(parts) == 4:
-    group, artifact, version, classifier = parts
+  if repository.startswith(MAVEN_SNAPSHOT):
+    jar, url = maven_snapshot(parts)
   else:
-    group, artifact, version = parts
-    classifier = None
-
-  # SNAPSHOT artifacts are handled differently on Google storage bucket:
-  # 'SNAPSHOT' is discarded from the directory name. However on other
-  # Maven repositories, most notable local repository located in
-  # ~/.m2/repository (and is supported through MAVEN_LOCAL repository)
-  # it must be preserved, otherwise the artifact wouldn't be found.
-  # Atm the SNAPSHOT part is only discarded for Google storage bucket.
-  if 'SNAPSHOT' in version and repository.startswith(GERRIT):
-    file_version = version.replace('-SNAPSHOT', '')
-    version = version.split('-SNAPSHOT')[0] + '-SNAPSHOT'
-  else:
-    file_version = version
-
-  if classifier is not None:
-    file_version += '-' + classifier
-
-  jar = path.join(name, artifact.lower() + '-' + file_version)
-
-  url = '/'.join([
-    repository,
-    group.replace('.', '/'), artifact, version,
-    artifact + '-' + file_version])
+    jar, url = maven_release(parts)
 
   binjar = jar + '.jar'
   binurl = url + '.jar'
diff --git a/plugins/cookbook-plugin b/plugins/cookbook-plugin
index 65200f1..97c7ccf 160000
--- a/plugins/cookbook-plugin
+++ b/plugins/cookbook-plugin
@@ -1 +1 @@
-Subproject commit 65200f113220802a7d74ef9e809d899843f2bcc1
+Subproject commit 97c7ccfd62028c0fd7cb88db5567a0f20fc9f09b
diff --git a/plugins/replication b/plugins/replication
index 8419e92..d5cd908 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit 8419e92cb014c1fa5a1f1757e187bf880f99b476
+Subproject commit d5cd908c0d7938a5d253d49f68ed352bbc7449cf
diff --git a/plugins/reviewnotes b/plugins/reviewnotes
index 0ea78c9..c167df0 160000
--- a/plugins/reviewnotes
+++ b/plugins/reviewnotes
@@ -1 +1 @@
-Subproject commit 0ea78c9ca7c70515c81681af05a65ec4dc32a542
+Subproject commit c167df08a8550d8c6c7ccf12b7df4fa6bfc6d432
diff --git a/polygerrit-ui/app/behaviors/rest-client-behavior.html b/polygerrit-ui/app/behaviors/rest-client-behavior.html
index f6897cd..c515664 100644
--- a/polygerrit-ui/app/behaviors/rest-client-behavior.html
+++ b/polygerrit-ui/app/behaviors/rest-client-behavior.html
@@ -102,6 +102,11 @@
     changePath: function(changeNum) {
       return '/c/' + changeNum;
     },
+
+    changeIsOpen: function(status) {
+      return status === this.ChangeStatus.NEW ||
+          status === this.ChangeStatus.DRAFT;
+    },
   };
 
   window.Gerrit = window.Gerrit || {};
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js
index bcceb35..d160933 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js
@@ -127,7 +127,7 @@
     },
 
     _computeProjectURL: function(project) {
-      return '/projects/' + project + ',dashboards/default';
+      return '/q/status:open+project:' + project;
     },
 
     _computeProjectBranchURL: function(project, branch) {
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.html b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.html
index 8447215..5507b9f 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.html
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.html
@@ -118,7 +118,7 @@
           {labels: {Verified: {rejected: true}}}, 'Verified'), '✕');
 
       assert.equal(element._computeProjectURL('combustible-stuff'),
-          '/projects/combustible-stuff,dashboards/default');
+          '/q/status:open+project:combustible-stuff');
 
       assert.equal(element._computeProjectBranchURL(
           'combustible-stuff', 'lemons'),
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.html b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.html
index 6788cce..f71d0f7 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.html
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.html
@@ -25,12 +25,10 @@
       :host {
         background-color: var(--view-background-color);
         display: block;
-        margin: 0 var(--default-horizontal-margin);
       }
       .loading,
       .error {
-        margin-top: 1em;
-        background-color: #f1f2f3;
+        padding: 1em var(--default-horizontal-margin);
       }
       .loading {
         color: #666;
@@ -39,11 +37,9 @@
         color: #D32F2F;
       }
       gr-change-list {
-        margin-top: 1em;
         width: 100%;
       }
       nav {
-        margin-bottom: 1em;
         padding: .5em 0;
         text-align: center;
       }
@@ -54,9 +50,6 @@
         margin-right: .5em;
       }
       @media only screen and (max-width: 50em) {
-        :host {
-          margin: 0;
-        }
         .loading,
         .error {
           padding: 0 var(--default-horizontal-margin);
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js
index ef71be3..d1b2456 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js
@@ -119,7 +119,7 @@
 
     _computeItemNeedsReview: function(account, change, showReviewedState) {
       return showReviewedState && !change.reviewed &&
-          change.status != this.ChangeStatus.MERGED &&
+          this.changeIsOpen(change.status) &&
           account._account_id != change.owner._account_id;
     },
 
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html
index 25f6d80..f8f34da 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html
@@ -108,48 +108,58 @@
       element.changes = [
         {
           _number: 0,
+          status: 'NEW',
           reviewed: true,
-          owner: { _account_id: 0 },
+          owner: {_account_id: 0},
         },
         {
           _number: 1,
-          owner: { _account_id: 0 },
+          status: 'NEW',
+          owner: {_account_id: 0},
         },
         {
           _number: 2,
           status: 'MERGED',
-          owner: { _account_id: 0 },
+          owner: {_account_id: 0},
         },
         {
           _number: 3,
-          owner: { _account_id: 42 },
+          status: 'DRAFT',
+          owner: {_account_id: 42},
+        },
+        {
+          _number: 4,
+          status: 'ABANDONED',
+          owner: {_account_id: 0},
         }
       ];
       flushAsynchronousOperations();
       var elementItems = Polymer.dom(element.root).querySelectorAll(
           'gr-change-list-item');
-      assert.equal(elementItems.length, 4);
+      assert.equal(elementItems.length, 5);
       for (var i = 0; i < elementItems.length; i++) {
         assert.isFalse(elementItems[i].hasAttribute('needs-review'));
       }
 
       element.showReviewedState = true;
-      var elementItems = Polymer.dom(element.root).querySelectorAll(
+      elementItems = Polymer.dom(element.root).querySelectorAll(
           'gr-change-list-item');
-      assert.equal(elementItems.length, 4);
+      assert.equal(elementItems.length, 5);
       assert.isFalse(elementItems[0].hasAttribute('needs-review'));
       assert.isTrue(elementItems[1].hasAttribute('needs-review'));
       assert.isFalse(elementItems[2].hasAttribute('needs-review'));
       assert.isTrue(elementItems[3].hasAttribute('needs-review'));
+      assert.isFalse(elementItems[4].hasAttribute('needs-review'));
 
-      element.account = { _account_id: 42 };
-      var elementItems = Polymer.dom(element.root).querySelectorAll(
+      element.account = {_account_id: 42};
+      elementItems = Polymer.dom(element.root).querySelectorAll(
           'gr-change-list-item');
-      assert.equal(elementItems.length, 4);
+      assert.equal(elementItems.length, 5);
       assert.isFalse(elementItems[0].hasAttribute('needs-review'));
       assert.isTrue(elementItems[1].hasAttribute('needs-review'));
       assert.isFalse(elementItems[2].hasAttribute('needs-review'));
       assert.isFalse(elementItems[3].hasAttribute('needs-review'));
+      assert.isFalse(elementItems[4].hasAttribute('needs-review'));
     });
 
     test('no changes', function() {
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.html b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.html
index e351f44..fb2de62 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.html
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.html
@@ -23,21 +23,15 @@
       :host {
         background-color: var(--view-background-color);
         display: block;
-        margin: 0 var(--default-horizontal-margin);
       }
       .loading {
-        margin-top: 1em;
         color: #666;
-        background-color: #f1f2f3;
+        padding: 1em var(--default-horizontal-margin);
       }
       gr-change-list {
-        margin-top: 1em;
         width: 100%;
       }
       @media only screen and (max-width: 50em) {
-        :host {
-          margin: 0;
-        }
         .loading {
           padding: 0 var(--default-horizontal-margin);
         }
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
index d201447..5e351e7 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
@@ -83,6 +83,8 @@
 
       this._loading = true;
       return this._getRevisionActions().then(function(revisionActions) {
+        if (!revisionActions) { return; }
+
         this._revisionActions = revisionActions;
         this._loading = false;
       }.bind(this)).catch(function(err) {
@@ -90,7 +92,7 @@
             'and contact the PolyGerrit team for assistance.');
         this._loading = false;
         throw err;
-      });
+      }.bind(this));
     },
 
     _getRevisionActions: function() {
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js
index f6733d1..4fa98ca 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js
@@ -36,9 +36,7 @@
     ],
 
     _computeHideStrategy: function(change) {
-      var open = change.status == this.ChangeStatus.NEW ||
-          change.status == this.ChangeStatus.DRAFT;
-      return !open;
+      return !this.changeIsOpen(change.status);
     },
 
     _computeStrategy: function(change) {
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
index 8b77489..2442222 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
@@ -36,14 +36,12 @@
 <dom-module id="gr-change-view">
   <template>
     <style>
-      .container {
-        margin: 1em var(--default-horizontal-margin);
-      }
       .container:not(.loading) {
         background-color: var(--view-background-color);
       }
       .container.loading {
         color: #666;
+        padding: 1em var(--default-horizontal-margin);
       }
       .headerContainer {
         height: 4.1em;
@@ -63,7 +61,7 @@
         position: fixed;
         top: 0;
         transition: box-shadow 250ms linear;
-        width: calc(100% - (2 * var(--default-horizontal-margin)));
+        width: 100%;
       }
       .header-title {
         flex: 1;
@@ -137,36 +135,29 @@
         align-content: flex-start;
         display: flex;
         flex: 1;
-        flex-wrap: wrap;
         overflow-x: hidden;
       }
+      .relatedChanges {
+        flex: 1 1 auto;
+        font-size: .9em;
+        overflow: hidden;
+      }
       gr-file-list {
         margin-bottom: 1em;
         padding: 0 var(--default-horizontal-margin);
       }
       @media screen and (max-width: 50em) {
-        .container {
-          margin: .5em 0 !important;
-        }
-        .container.loading {
-          margin: 1em var(--default-horizontal-margin) !important;
-        }
         .headerContainer {
           height: 5.15em;
         }
         .header {
           align-items: flex-start;
           flex-direction: column;
-          padding: .5em var(--default-horizontal-margin) !important;
+          padding: .5em var(--default-horizontal-margin);
         }
         gr-change-star {
           vertical-align: middle;
         }
-        .header-title,
-        .header-actions,
-        .header.pinned {
-          width: 100% !important;
-        }
         .header-title {
           font-size: 1.1em;
         }
@@ -184,15 +175,15 @@
           display: none;
         }
         .patchSelectLabel {
-          margin-left: 0 !important;
+          margin-left: 0;
           margin-right: .5em;
         }
         .header select {
-          margin-left: 0 !important;
+          margin-left: 0;
           margin-right: .5em;
         }
         .header .reply {
-          margin-left: 0 !important;
+          margin-left: 0;
           margin-right: .5em;
         }
         .changeInfo-column:not(:last-of-type) {
@@ -204,8 +195,11 @@
           flex-direction: column;
           flex-wrap: nowrap;
         }
+        .relatedChanges,
         .changeMetadata {
           font-size: 1em;
+        }
+        .changeMetadata {
           border-right: none;
           margin-bottom: 1em;
           margin-top: .25em;
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
index 27e2cb8..f3ccfc2 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
@@ -393,8 +393,6 @@
       this._getComments();
 
       var reloadPatchNumDependentResources = function() {
-        if (!this._change) { return Promise.resolve(); }
-
         return Promise.all([
           this._getCommitInfo(),
           this.$.actions.reload(),
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
index 39e50a9..de28184 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
@@ -126,21 +126,8 @@
     },
 
     _getFiles: function() {
-      return this.$.restAPI.getChangeFiles(this.changeNum, this.patchNum).then(
-          this._normalizeFilesResponse.bind(this));
-    },
-
-    _normalizeFilesResponse: function(response) {
-      var paths = Object.keys(response).sort();
-      var files = [];
-      for (var i = 0; i < paths.length; i++) {
-        var info = response[paths[i]];
-        info.__path = paths[i];
-        info.lines_inserted = info.lines_inserted || 0;
-        info.lines_deleted = info.lines_deleted || 0;
-        files.push(info);
-      }
-      return files;
+      return this.$.restAPI.getChangeFilesAsSpeciallySortedArray(
+          this.changeNum, this.patchNum);
     },
 
     _handleKey: function(e) {
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.html b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.html
index e93d008..2b13dd6 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.html
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.html
@@ -33,6 +33,16 @@
       a {
         display: block;
       }
+      .changeContainer,
+      a {
+        max-width: 100%;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+      }
+      .changeContainer {
+        display: flex;
+      }
       .relatedChanges a {
         display: inline-block;
       }
@@ -43,6 +53,7 @@
       .status {
         color: #666;
         font-weight: bold;
+        margin-left: .25em;
       }
       .notCurrent {
         color: #e65100;
@@ -78,9 +89,9 @@
 
     <div hidden$="[[!_loading]]">Loading...</div>
     <section class="relatedChanges" hidden$="[[!_relatedResponse.changes.length]]" hidden>
-      <h4>Relation Chain</h4>
+      <h4>Relation chain</h4>
       <template is="dom-repeat" items="[[_relatedResponse.changes]]" as="change">
-        <div>
+        <div class="changeContainer">
           <a href$="[[_computeChangeURL(change._change_number, change._revision_number)]]"
               class$="[[_computeLinkClass(change)]]">
             [[change.commit.subject]]
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
index 137162f..5308b11 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
@@ -29,7 +29,6 @@
         display: block;
       }
       h3 {
-        margin-top: 1em;
         padding: .75em var(--default-horizontal-margin);
       }
       .reviewed {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
index c4f2a83..12d7f69 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
@@ -109,9 +109,9 @@
     },
 
     _getFiles: function(changeNum, patchNum) {
-      return this.$.restAPI.getChangeFiles(changeNum, patchNum).then(
-          function(files) {
-            this._fileList = Object.keys(files).sort();
+      return this.$.restAPI.getChangeFilePathsAsSpeciallySortedArray(
+          changeNum, patchNum).then(function(files) {
+            this._fileList = files;
           }.bind(this));
     },
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-builder.js b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-builder.js
index f5e7c4c..19d87e9 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-builder.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-builder.js
@@ -431,14 +431,15 @@
       html = this._addIntralineHighlights(text, html, line.highlights);
     }
 
-    if (text.length > this._prefs.line_length) {
+    if (this._textLength(text, this._prefs.tab_size) >
+        this._prefs.line_length) {
       html = this._addNewlines(text, html);
     }
     html = this._addTabWrappers(html);
 
     // If the html is equivalent to the text then it didn't get highlighted
     // or escaped. Use textContent which is faster than innerHTML.
-    if (html == text) {
+    if (html === text) {
       td.textContent = text;
     } else {
       td.innerHTML = html;
@@ -446,6 +447,19 @@
     return td;
   };
 
+  GrDiffBuilder.prototype._textLength = function(text, tabSize) {
+    // TODO(andybons): Unicode support.
+    var numChars = 0;
+    for (var i = 0; i < text.length; i++) {
+      if (text[i] === '\t') {
+        numChars += tabSize;
+      } else {
+        numChars++;
+      }
+    }
+    return numChars;
+  };
+
   // Advance `index` by the appropriate number of characters that would
   // represent one source code character and return that index. For
   // example, for source code '<span>' the escaped html string is
@@ -553,10 +567,10 @@
     if (showTabs) {
       str += 'withIndicator';
     }
-    str += '" ';
+    str += '" style="';
     // TODO(andybons): CSS tab-size is not supported in IE.
-    str += 'style="tab-size:' + tabSize + ';';
-    str += 'style="-moz-tab-size:' + tabSize + ';';
+    str += 'tab-size:' + tabSize + ';';
+    str += '-moz-tab-size:' + tabSize + ';';
     str += '">\t</span>';
     return str;
   };
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-builder_test.html b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-builder_test.html
index 2e30999..f552260 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-builder_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-builder_test.html
@@ -259,6 +259,11 @@
           '6789');
     });
 
+    test('text length with tabs', function() {
+      assert.equal(builder._textLength('12345', 4), 5);
+      assert.equal(builder._textLength('\t\t12', 4), 10);
+    });
+
     test('tab wrapper insertion', function() {
       var html = 'abc\tdef';
       var wrapper = builder._getTabWrapper(
diff --git a/polygerrit-ui/app/elements/gr-app.html b/polygerrit-ui/app/elements/gr-app.html
index 723766d..dda0ae2 100644
--- a/polygerrit-ui/app/elements/gr-app.html
+++ b/polygerrit-ui/app/elements/gr-app.html
@@ -36,17 +36,21 @@
   <template>
     <style>
       :host {
-        background-color: var(--secondary-color);
         display: flex;
         min-height: 100vh;
         flex-direction: column;
       }
       gr-main-header,
       footer {
-        background-color: var(--primary-color);
         color: var(--primary-text-color);
         padding: .5rem var(--default-horizontal-margin);
       }
+      gr-main-header {
+        background-color: var(--header-background-color, #eee);
+      }
+      footer {
+        background-color: var(--footer-background-color, #eee);
+      }
       main {
         flex: 1;
         position: relative;
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
index c84c3e8..affbd06 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
@@ -238,6 +238,67 @@
           this.getChangeActionURL(changeNum, patchNum, '/files'));
     },
 
+    getChangeFilesAsSpeciallySortedArray: function(changeNum, patchNum) {
+      return this.getChangeFiles(changeNum, patchNum).then(
+          this._normalizeChangeFilesResponse.bind(this));
+    },
+
+    getChangeFilePathsAsSpeciallySortedArray: function(changeNum, patchNum) {
+      return this.getChangeFiles(changeNum, patchNum).then(function(files) {
+        return Object.keys(files).sort(this._specialFilePathCompare.bind(this));
+      }.bind(this));
+    },
+
+    _normalizeChangeFilesResponse: function(response) {
+      var paths = Object.keys(response).sort(
+          this._specialFilePathCompare.bind(this));
+      var files = [];
+      for (var i = 0; i < paths.length; i++) {
+        var info = response[paths[i]];
+        info.__path = paths[i];
+        info.lines_inserted = info.lines_inserted || 0;
+        info.lines_deleted = info.lines_deleted || 0;
+        files.push(info);
+      }
+      return files;
+    },
+
+    _specialFilePathCompare: function(a, b) {
+      var COMMIT_MESSAGE_PATH = '/COMMIT_MSG';
+      // The commit message always goes first.
+      if (a === COMMIT_MESSAGE_PATH) {
+        return -1;
+      }
+      if (b === COMMIT_MESSAGE_PATH) {
+        return 1;
+      }
+
+      var aLastDotIndex = a.lastIndexOf('.');
+      var aExt = a.substr(aLastDotIndex + 1);
+      var aFile = a.substr(0, aLastDotIndex);
+
+      var bLastDotIndex = b.lastIndexOf('.');
+      var bExt = b.substr(bLastDotIndex + 1);
+      var bFile = a.substr(0, bLastDotIndex);
+
+      // Sort header files above others with the same base name.
+      var headerExts = ['h', 'hxx', 'hpp'];
+      if (aFile.length > 0 && aFile === bFile) {
+        if (headerExts.indexOf(aExt) !== -1 &&
+            headerExts.indexOf(bExt) !== -1) {
+          return a.localeCompare(b);
+        }
+        if (headerExts.indexOf(aExt) !== -1) {
+          return -1;
+        }
+        if (headerExts.indexOf(bExt) !== -1) {
+          return 1;
+        }
+      }
+
+      return a.localeCompare(b);
+    },
+
     getChangeRevisionActions: function(changeNum, patchNum) {
       return this.fetchJSON(
           this.getChangeActionURL(changeNum, patchNum, '/actions'));
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
index 4e2c5ad..752d718 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
@@ -196,5 +196,31 @@
         });
     });
 
+    test('special file path sorting', function() {
+      assert.deepEqual(
+          ['.b', '/COMMIT_MSG', '.a', 'file'].sort(
+              element._specialFilePathCompare),
+          ['/COMMIT_MSG', '.a', '.b', 'file']);
+
+      assert.deepEqual(
+          ['.b', '/COMMIT_MSG', 'foo/bar/baz.cc', 'foo/bar/baz.h'].sort(
+              element._specialFilePathCompare),
+          ['/COMMIT_MSG', '.b', 'foo/bar/baz.h', 'foo/bar/baz.cc']);
+
+      assert.deepEqual(
+          ['.b', '/COMMIT_MSG', 'foo/bar/baz.cc', 'foo/bar/baz.hpp'].sort(
+              element._specialFilePathCompare),
+          ['/COMMIT_MSG', '.b', 'foo/bar/baz.hpp', 'foo/bar/baz.cc']);
+
+      assert.deepEqual(
+          ['.b', '/COMMIT_MSG', 'foo/bar/baz.cc', 'foo/bar/baz.hxx'].sort(
+              element._specialFilePathCompare),
+          ['/COMMIT_MSG', '.b', 'foo/bar/baz.hxx', 'foo/bar/baz.cc']);
+
+      assert.deepEqual(
+          ['foo/bar.h', 'foo/bar.hxx', 'foo/bar.hpp'].sort(
+              element._specialFilePathCompare),
+          ['foo/bar.h', 'foo/bar.hpp', 'foo/bar.hxx']);
+    });
   });
 </script>
diff --git a/polygerrit-ui/app/index.html b/polygerrit-ui/app/index.html
index 4dad2b9..0e00f77 100644
--- a/polygerrit-ui/app/index.html
+++ b/polygerrit-ui/app/index.html
@@ -20,6 +20,7 @@
 <meta name="description" content="Gerrit Code Review">
 <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
 
+<link rel="stylesheet" href="/styles/fonts.css">
 <link rel="stylesheet" href="/styles/main.css">
 <script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
 <link rel="import" href="/elements/gr-app.html">
diff --git a/polygerrit-ui/app/styles/app-theme.html b/polygerrit-ui/app/styles/app-theme.html
index 81c6ff7..cf54b5d 100644
--- a/polygerrit-ui/app/styles/app-theme.html
+++ b/polygerrit-ui/app/styles/app-theme.html
@@ -15,10 +15,8 @@
 -->
 <style is="custom-style">
 :root {
-  --primary-color: #fff;
   --primary-text-color: #000;
   --search-border-color: #ddd;
-  --secondary-color: #f1f2f3;
   --selection-background-color: #ebf5fb;
   --default-text-color: #000;
   --view-background-color: #fff;
diff --git a/polygerrit-ui/app/styles/main.css b/polygerrit-ui/app/styles/main.css
index 5c5ad96..9bf33a0 100644
--- a/polygerrit-ui/app/styles/main.css
+++ b/polygerrit-ui/app/styles/main.css
@@ -14,8 +14,6 @@
 limitations under the License.
 */
 
-@import "fonts.css";
-
 *,
 *::after,
 *::before {
diff --git a/tools/checkstyle.xml b/tools/checkstyle.xml
index 1bb40f7..cb24e8f 100644
--- a/tools/checkstyle.xml
+++ b/tools/checkstyle.xml
@@ -93,6 +93,10 @@
       <property name="tokens" value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR, LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR "/>
       <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
     </module>
+    <module name="RedundantImport"/>
+    <module name="RedundantModifier"/>
+    <module name="ExplicitInitialization"/>
+    <module name="ArrayTrailingComma"/>
   </module>
   <module name="FileTabCharacter">
     <property name="severity" value="ignore"/>
diff --git a/tools/eclipse/gerrit_gwt_debug.launch b/tools/eclipse/gerrit_gwt_debug.launch
index c3c58ff..b2ab320 100644
--- a/tools/eclipse/gerrit_gwt_debug.launch
+++ b/tools/eclipse/gerrit_gwt_debug.launch
@@ -16,7 +16,7 @@
 </listAttribute>
 <booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
 <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gerrit.gwtdebug.GerritGwtDebugLauncher"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-noprecompile -src ${resource_loc:/gerrit} -workDir ${resource_loc:/gerrit}/buck-out/gen/gerrit-gwtui com.google.gerrit.GerritGwtUI -src ${resource_loc:/gerrit}/gerrit-plugin-gwtui/src/main/java -- --console-log --show-stack-trace -d ${resource_loc:/gerrit}/../gerrit_testsite"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-strict -noprecompile -src ${resource_loc:/gerrit} -workDir ${resource_loc:/gerrit}/buck-out/gen/gerrit-gwtui com.google.gerrit.GerritGwtUI -src ${resource_loc:/gerrit}/gerrit-plugin-gwtui/src/main/java -- --console-log --show-stack-trace -d ${resource_loc:/gerrit}/../gerrit_testsite"/>
 <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="gerrit"/>
 <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx1024M&#10;-XX:MaxPermSize=256M&#10;-Dgerrit.disable-gwtui-recompile=true"/>
 </launchConfiguration>
diff --git a/tools/util.py b/tools/util.py
index 96f6047..08a803f 100644
--- a/tools/util.py
+++ b/tools/util.py
@@ -20,6 +20,7 @@
   'GERRIT_API': 'https://gerrit-api.commondatastorage.googleapis.com/release',
   'MAVEN_CENTRAL': 'http://repo1.maven.org/maven2',
   'MAVEN_LOCAL': 'file://' + path.expanduser('~/.m2/repository'),
+  'MAVEN_SNAPSHOT': 'https://oss.sonatype.org/content/repositories/snapshots',
 }