Merge "Emails: Retry failed index queries when querying accounts by preferred email"
diff --git a/Documentation/images/intro-quick-new-review.jpg b/Documentation/images/intro-quick-new-review.jpg
deleted file mode 100644
index 99e6c55..0000000
--- a/Documentation/images/intro-quick-new-review.jpg
+++ /dev/null
Binary files differ
diff --git a/Documentation/images/intro-quick-new-review.png b/Documentation/images/intro-quick-new-review.png
new file mode 100644
index 0000000..36d93e9
--- /dev/null
+++ b/Documentation/images/intro-quick-new-review.png
Binary files differ
diff --git a/Documentation/images/intro-quick-review-2-patches.jpg b/Documentation/images/intro-quick-review-2-patches.jpg
deleted file mode 100644
index 29c99cc..0000000
--- a/Documentation/images/intro-quick-review-2-patches.jpg
+++ /dev/null
Binary files differ
diff --git a/Documentation/images/intro-quick-review-2-patches.png b/Documentation/images/intro-quick-review-2-patches.png
new file mode 100644
index 0000000..d7e9129
--- /dev/null
+++ b/Documentation/images/intro-quick-review-2-patches.png
Binary files differ
diff --git a/Documentation/images/intro-quick-review-line-comment.jpg b/Documentation/images/intro-quick-review-line-comment.jpg
deleted file mode 100644
index eeb144a..0000000
--- a/Documentation/images/intro-quick-review-line-comment.jpg
+++ /dev/null
Binary files differ
diff --git a/Documentation/images/intro-quick-review-line-comment.png b/Documentation/images/intro-quick-review-line-comment.png
new file mode 100644
index 0000000..7964365
--- /dev/null
+++ b/Documentation/images/intro-quick-review-line-comment.png
Binary files differ
diff --git a/Documentation/images/intro-quick-reviewing-the-change.jpg b/Documentation/images/intro-quick-reviewing-the-change.jpg
deleted file mode 100644
index bfded9e..0000000
--- a/Documentation/images/intro-quick-reviewing-the-change.jpg
+++ /dev/null
Binary files differ
diff --git a/Documentation/images/intro-quick-reviewing-the-change.png b/Documentation/images/intro-quick-reviewing-the-change.png
new file mode 100644
index 0000000..bdce6bd
--- /dev/null
+++ b/Documentation/images/intro-quick-reviewing-the-change.png
Binary files differ
diff --git a/Documentation/images/intro-quick-verifying.jpg b/Documentation/images/intro-quick-verifying.jpg
deleted file mode 100644
index 7679c0a..0000000
--- a/Documentation/images/intro-quick-verifying.jpg
+++ /dev/null
Binary files differ
diff --git a/Documentation/images/intro-quick-verifying.png b/Documentation/images/intro-quick-verifying.png
new file mode 100644
index 0000000..e343cc9
--- /dev/null
+++ b/Documentation/images/intro-quick-verifying.png
Binary files differ
diff --git a/Documentation/intro-gerrit-walkthrough.txt b/Documentation/intro-gerrit-walkthrough.txt
index fcb4de2..1fba1dc 100644
--- a/Documentation/intro-gerrit-walkthrough.txt
+++ b/Documentation/intro-gerrit-walkthrough.txt
@@ -4,7 +4,7 @@
 life cycle. This example uses a Gerrit server configured as follows:
 
 * *Hostname*: gerrithost
-* *HTTP interface port*: 8080
+* *HTTP interface port*: 80
 * *SSH interface port*: 29418
 
 In this walkthrough, we'll follow two developers, Max and Hannah, as they make
@@ -52,19 +52,20 @@
 ----
 $ <work>
 $ git commit
-[master 9651f22] Change to a proper, yeast based pizza dough.
- 1 files changed, 3 insertions(+), 2 deletions(-)
+[master 3cc9e62] Change to a proper, yeast based pizza dough.
+ 1 file changed, 10 insertions(+), 5 deletions(-)
 $ git push origin HEAD:refs/for/master
-Counting objects: 5, done.
+Counting objects: 3, done.
 Delta compression using up to 8 threads.
 Compressing objects: 100% (2/2), done.
-Writing objects: 100% (3/3), 542 bytes, done.
+Writing objects: 100% (3/3), 532 bytes | 0 bytes/s, done.
 Total 3 (delta 0), reused 0 (delta 0)
+remote: Processing changes: new: 1, done
 remote:
 remote: New Changes:
-remote:   http://gerrithost:8080/68
+remote:   http://gerrithost/#/c/RecipeBook/+/702 Change to a proper, yeast based pizza dough.
 remote:
-To ssh://gerrithost:29418/RecipeBook.git
+To ssh://gerrithost:29418/RecipeBook
  * [new branch]      HEAD -> refs/for/master
 ----
 
@@ -79,7 +80,7 @@
 the following.
 
 .Gerrit Code Review Screen
-image::images/intro-quick-new-review.jpg[Gerrit Review Screen]
+image::images/intro-quick-new-review.png[Gerrit Review Screen]
 
 This is the Gerrit code review screen, where other contributors can review
 his change. Max can also perform tasks such as:
@@ -109,14 +110,12 @@
 Because Max added Hannah as a reviewer, she receives an email telling her about
 his change. She opens up the Gerrit code review screen and selects Max's change.
 
-.Gerrit Code Review Screen
-image::images/intro-quick-new-review.jpg[Gerrit Review Screen]
-
-Notice the two "Need" lines:
+Notice the *Label status* section above:
 
 ----
-* Need Verified
-* Need Code-Review
+Label Status Needs label:
+             * Code-Review
+             * Verified
 ----
 
 These two lines indicate what checks must be completed before the change is
@@ -147,13 +146,13 @@
 Hannah opts to view the change using Gerrit's side-by-side view:
 
 .Side By Side Patch View
-image::images/intro-quick-review-line-comment.jpg[Adding a Comment]
+image::images/intro-quick-review-line-comment.png[Adding a Comment]
 
 Hannah reviews the change and is ready to provide her feedback. She clicks the
-*Review* button on the change screen. This allows her to vote on the change.
+*REPLY* button on the change screen. This allows her to vote on the change.
 
 .Reviewing the Change
-image::images/intro-quick-reviewing-the-change.jpg[Reviewing the Change]
+image::images/intro-quick-reviewing-the-change.png[Reviewing the Change]
 
 For Hannah and Max's team, a code review vote is a numerical score between -2
 and 2. The possible options are:
@@ -175,7 +174,7 @@
 Hannah notices a possible issue with Max's change, so she selects a `-1` vote.
 She uses the *Cover Message* text box to provide Max with some additional
 feedback. When she is satisfied with her review, Hannah clicks the
-*Publish Comments* button. At this point, her vote and cover message become
+*SEND* button. At this point, her vote and cover message become
 visible to to all users.
 
 == Reworking the Change
@@ -193,18 +192,21 @@
 $ <checkout first commit>
 $ <rework>
 $ git commit --amend
+[master 30a6f44] Change to a proper, yeast based pizza dough.
+ Date: Fri Jun 8 16:28:23 2018 +0200
+ 1 file changed, 10 insertions(+), 5 deletions(-)
 $ git push origin HEAD:refs/for/master
-Counting objects: 5, done.
+Counting objects: 3, done.
 Delta compression using up to 8 threads.
 Compressing objects: 100% (2/2), done.
-Writing objects: 100% (3/3), 546 bytes, done.
+Writing objects: 100% (3/3), 528 bytes | 0 bytes/s, done.
 Total 3 (delta 0), reused 0 (delta 0)
 remote: Processing changes: updated: 1, done
 remote:
 remote: Updated Changes:
-remote:   http://gerrithost:8080/68
+remote:   http://gerrithost/#/c/RecipeBook/+/702 Change to a proper, yeast based pizza dough.
 remote:
-To ssh://gerrithost:29418/RecipeBook.git
+To ssh://gerrithost:29418/RecipeBook
  * [new branch]      HEAD -> refs/for/master
 ----
 
@@ -212,13 +214,10 @@
 commit. This time, the output verifies that the change was updated.
 
 Having uploaded the reworked commit, Max can go back to the Gerrit web
-interface and look at his change.
-
-.Reviewing the Rework
-image::images/intro-quick-review-2-patches.jpg[Reviewing the Rework]
-
-Notice that there are now two patch sets associated with this change: the
-initial submission and the rework.
+interface, look at his change and diff the first patch set with his rework in
+the second one. Once he has verified that the rework follows Hannahs
+recommendation he presses the *DONE* button to let Hannah know that she can
+review the changes.
 
 When Hannah next looks at Max's change, she sees that he incorporated her
 feedback. The change looks good to her, so she changes her vote to a `+2`.
@@ -254,7 +253,7 @@
 different person entirely.
 
 .Verifying the Change
-image::images/intro-quick-verifying.jpg[Verifying the Change]
+image::images/intro-quick-verifying.png[Verifying the Change]
 
 Unlike the code review check, the verify check is pass/fail. Hannah can provide
 a score of either `+1` or `-1`. A change must have at least one `+1` and no
@@ -266,7 +265,7 @@
 == Submitting the Change
 
 Max is now ready to submit his change. He opens up the change in the Code Review
-screen and clicks the *Publish and Submit* button.
+screen and clicks the *SUBMIT* button.
 
 At this point, Max's change is merged into the repository's master branch and
 becomes an accepted part of the project.
diff --git a/Documentation/intro-user.txt b/Documentation/intro-user.txt
index f5042a7..436408d 100644
--- a/Documentation/intro-user.txt
+++ b/Documentation/intro-user.txt
@@ -548,6 +548,9 @@
 ----
 Alternatively, click *Ready* from the Change screen.
 
+Only change owners, project owners and site administrators can mark changes as
+`work-in-progress` and `ready`.
+
 [[wip-polygerrit]]
 In the new PolyGerrit UI, you can mark a change as WIP, by selecting *WIP* from
 the *More* menu. The Change screen updates with a yellow header, indicating that
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index 8d1b2d8..e64bdb3 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -2145,7 +2145,8 @@
 'POST /changes/link:#change-id[\{change-id\}]/wip'
 --
 
-Marks the change as not ready for review yet.
+Marks the change as not ready for review yet. Changes may only be marked not
+ready by the owner, project owners or site administrators.
 
 The request body does not need to include a
 link:#work-in-progress-input[WorkInProgressInput] entity if no review comment
@@ -2173,7 +2174,8 @@
 'POST /changes/link:#change-id[\{change-id\}]/ready'
 --
 
-Marks the change as ready for review (set WIP property to false).
+Marks the change as ready for review (set WIP property to false). Changes may
+only be marked ready by the owner, project owners or site administrators.
 
 Activates notifications of reviewer. The request body does not need
 to include a link:#work-in-progress-input[WorkInProgressInput] entity
diff --git a/Documentation/user-upload.txt b/Documentation/user-upload.txt
index c12a38c..ce62b93 100644
--- a/Documentation/user-upload.txt
+++ b/Documentation/user-upload.txt
@@ -306,6 +306,9 @@
   git push ssh://john.doe@git.example.com:29418/kernel/common HEAD:refs/for/master%ready
 ----
 
+Only change owners, project owners and site administrators can specify
+`work-in-progress` and `ready` options on push.
+
 [[message]]
 ==== Message
 
diff --git a/WORKSPACE b/WORKSPACE
index bf207b5..bc21d01 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -46,7 +46,7 @@
 ANTLR_VERS = "3.5.2"
 
 maven_jar(
-    name = "java_runtime",
+    name = "java-runtime",
     artifact = "org.antlr:antlr-runtime:" + ANTLR_VERS,
     sha1 = "cd9cd41361c155f3af0f653009dcecb08d8b4afd",
 )
@@ -58,7 +58,7 @@
 )
 
 maven_jar(
-    name = "org_antlr",
+    name = "org-antlr",
     artifact = "org.antlr:antlr:" + ANTLR_VERS,
     sha1 = "c4a65c950bfc3e7d04309c515b2177c00baf7764",
 )
@@ -73,19 +73,19 @@
 GUICE_VERS = "4.2.0"
 
 maven_jar(
-    name = "guice_library",
+    name = "guice-library",
     artifact = "com.google.inject:guice:" + GUICE_VERS,
     sha1 = "25e1f4c1d528a1cffabcca0d432f634f3132f6c8",
 )
 
 maven_jar(
-    name = "guice_assistedinject",
+    name = "guice-assistedinject",
     artifact = "com.google.inject.extensions:guice-assistedinject:" + GUICE_VERS,
     sha1 = "e7270305960ad7db56f7e30cb9df6be9ff1cfb45",
 )
 
 maven_jar(
-    name = "guice_servlet",
+    name = "guice-servlet",
     artifact = "com.google.inject.extensions:guice-servlet:" + GUICE_VERS,
     sha1 = "f57581625c36c148f088d9f52a568d5bdf12c61d",
 )
@@ -103,7 +103,7 @@
 )
 
 maven_jar(
-    name = "servlet_api_3_1",
+    name = "servlet-api-3_1",
     artifact = "org.apache.tomcat:tomcat-servlet-api:8.5.23",
     sha1 = "021a212688ec94fe77aff74ab34cc74f6f940e60",
 )
@@ -123,14 +123,14 @@
 )
 
 maven_jar(
-    name = "javax_validation",
+    name = "javax-validation",
     artifact = "javax.validation:validation-api:1.0.0.GA",
     sha1 = "b6bd7f9d78f6fdaa3c37dae18a4bd298915f328e",
     src_sha1 = "7a561191db2203550fbfa40d534d4997624cd369",
 )
 
 maven_jar(
-    name = "jsinterop_annotations",
+    name = "jsinterop-annotations",
     artifact = "com.google.jsinterop:jsinterop-annotations:1.0.2",
     sha1 = "abd7319f53d018e11108a88f599bd16492448dd2",
     src_sha1 = "33716f8aef043f2f02b78ab4a1acda6cd90a7602",
@@ -158,7 +158,7 @@
 )
 
 maven_jar(
-    name = "w3c_css_sac",
+    name = "w3c-css-sac",
     artifact = "org.w3c.css:sac:1.3",
     sha1 = "cdb2dcb4e22b83d6b32b93095f644c3462739e82",
 )
@@ -208,7 +208,7 @@
 )
 
 maven_jar(
-    name = "gwtorm_client",
+    name = "gwtorm-client",
     artifact = "com.google.gerrit:gwtorm:1.18",
     sha1 = "f326dec463439a92ccb32f05b38345e21d0b5ecf",
     src_sha1 = "e0b973d5cafef3d145fa80cdf032fcead1186d29",
@@ -249,25 +249,25 @@
 SLF4J_VERS = "1.7.7"
 
 maven_jar(
-    name = "log_api",
+    name = "log-api",
     artifact = "org.slf4j:slf4j-api:" + SLF4J_VERS,
     sha1 = "2b8019b6249bb05d81d3a3094e468753e2b21311",
 )
 
 maven_jar(
-    name = "log_ext",
+    name = "log-ext",
     artifact = "org.slf4j:slf4j-ext:" + SLF4J_VERS,
     sha1 = "09a8f58c784c37525d2624062414358acf296717",
 )
 
 maven_jar(
-    name = "impl_log4j",
+    name = "impl-log4j",
     artifact = "org.slf4j:slf4j-log4j12:" + SLF4J_VERS,
     sha1 = "58f588119ffd1702c77ccab6acb54bfb41bed8bd",
 )
 
 maven_jar(
-    name = "jcl_over_slf4j",
+    name = "jcl-over-slf4j",
     artifact = "org.slf4j:jcl-over-slf4j:" + SLF4J_VERS,
     sha1 = "56003dcd0a31deea6391b9e2ef2f2dc90b205a92",
 )
@@ -279,13 +279,13 @@
 )
 
 maven_jar(
-    name = "jsonevent_layout",
+    name = "jsonevent-layout",
     artifact = "net.logstash.log4j:jsonevent-layout:1.7",
     sha1 = "507713504f0ddb75ba512f62763519c43cf46fde",
 )
 
 maven_jar(
-    name = "json_smart",
+    name = "json-smart",
     artifact = "net.minidev:json-smart:1.1.1",
     sha1 = "24a2f903d25e004de30ac602c5b47f2d4e420a59",
 )
@@ -297,50 +297,50 @@
 )
 
 maven_jar(
-    name = "commons_codec",
+    name = "commons-codec",
     artifact = "commons-codec:commons-codec:1.10",
     sha1 = "4b95f4897fa13f2cd904aee711aeafc0c5295cd8",
 )
 
 # When upgrading commons-compress, also upgrade tukaani-xz
 maven_jar(
-    name = "commons_compress",
+    name = "commons-compress",
     artifact = "org.apache.commons:commons-compress:1.15",
     sha1 = "b686cd04abaef1ea7bc5e143c080563668eec17e",
 )
 
 maven_jar(
-    name = "commons_lang",
+    name = "commons-lang",
     artifact = "commons-lang:commons-lang:2.6",
     sha1 = "0ce1edb914c94ebc388f086c6827e8bdeec71ac2",
 )
 
 maven_jar(
-    name = "commons_lang3",
+    name = "commons-lang3",
     artifact = "org.apache.commons:commons-lang3:3.6",
     sha1 = "9d28a6b23650e8a7e9063c04588ace6cf7012c17",
 )
 
 maven_jar(
-    name = "commons_dbcp",
+    name = "commons-dbcp",
     artifact = "commons-dbcp:commons-dbcp:1.4",
     sha1 = "30be73c965cc990b153a100aaaaafcf239f82d39",
 )
 
 maven_jar(
-    name = "commons_pool",
+    name = "commons-pool",
     artifact = "commons-pool:commons-pool:1.5.5",
     sha1 = "7d8ffbdc47aa0c5a8afe5dc2aaf512f369f1d19b",
 )
 
 maven_jar(
-    name = "commons_net",
+    name = "commons-net",
     artifact = "commons-net:commons-net:3.6",
     sha1 = "b71de00508dcb078d2b24b5fa7e538636de9b3da",
 )
 
 maven_jar(
-    name = "commons_validator",
+    name = "commons-validator",
     artifact = "commons-validator:commons-validator:1.6",
     sha1 = "e989d1e87cdd60575df0765ed5bac65c905d7908",
 )
@@ -388,13 +388,13 @@
 MIME4J_VERS = "0.8.1"
 
 maven_jar(
-    name = "mime4j_core",
+    name = "mime4j-core",
     artifact = "org.apache.james:apache-mime4j-core:" + MIME4J_VERS,
     sha1 = "c62dfe18a3b827a2c626ade0ffba44562ddf3f61",
 )
 
 maven_jar(
-    name = "mime4j_dom",
+    name = "mime4j-dom",
     artifact = "org.apache.james:apache-mime4j-dom:" + MIME4J_VERS,
     sha1 = "f2d653c617004193f3350330d907f77b60c88c56",
 )
@@ -408,31 +408,31 @@
 OW2_VERS = "6.0"
 
 maven_jar(
-    name = "ow2_asm",
+    name = "ow2-asm",
     artifact = "org.ow2.asm:asm:" + OW2_VERS,
     sha1 = "bc6fa6b19424bb9592fe43bbc20178f92d403105",
 )
 
 maven_jar(
-    name = "ow2_asm_analysis",
+    name = "ow2-asm-analysis",
     artifact = "org.ow2.asm:asm-analysis:" + OW2_VERS,
     sha1 = "dd1cc1381a970800268160203aae2d3784da779b",
 )
 
 maven_jar(
-    name = "ow2_asm_commons",
+    name = "ow2-asm-commons",
     artifact = "org.ow2.asm:asm-commons:" + OW2_VERS,
     sha1 = "f256fd215d8dd5a4fa2ab3201bf653de266ed4ec",
 )
 
 maven_jar(
-    name = "ow2_asm_tree",
+    name = "ow2-asm-tree",
     artifact = "org.ow2.asm:asm-tree:" + OW2_VERS,
     sha1 = "a624f1a6e4e428dcd680a01bab2d4c56b35b18f0",
 )
 
 maven_jar(
-    name = "ow2_asm_util",
+    name = "ow2-asm-util",
     artifact = "org.ow2.asm:asm-util:" + OW2_VERS,
     sha1 = "430b2fc839b5de1f3643b528853d5cf26096c1de",
 )
@@ -440,20 +440,20 @@
 AUTO_VALUE_VERSION = "1.6"
 
 maven_jar(
-    name = "auto_value",
+    name = "auto-value",
     artifact = "com.google.auto.value:auto-value:" + AUTO_VALUE_VERSION,
     sha1 = "a3b1b1404f8acaa88594a017185e013cd342c9a8",
 )
 
 maven_jar(
-    name = "auto_value_annotations",
+    name = "auto-value-annotations",
     artifact = "com.google.auto.value:auto-value-annotations:" + AUTO_VALUE_VERSION,
     sha1 = "da725083ee79fdcd86d9f3d8a76e38174a01892a",
 )
 
 # Transitive dependency of commons-compress
 maven_jar(
-    name = "tukaani_xz",
+    name = "tukaani-xz",
     artifact = "org.tukaani:xz:1.6",
     sha1 = "05b6f921f1810bdf90e25471968f741f87168b64",
 )
@@ -461,37 +461,37 @@
 LUCENE_VERS = "5.5.4"
 
 maven_jar(
-    name = "lucene_core",
+    name = "lucene-core",
     artifact = "org.apache.lucene:lucene-core:" + LUCENE_VERS,
     sha1 = "ab9c77e75cf142aa6e284b310c8395617bd9b19b",
 )
 
 maven_jar(
-    name = "lucene_analyzers_common",
+    name = "lucene-analyzers-common",
     artifact = "org.apache.lucene:lucene-analyzers-common:" + LUCENE_VERS,
     sha1 = "08ce9d34c8124c80e176e8332ee947480bbb9576",
 )
 
 maven_jar(
-    name = "backward_codecs",
+    name = "backward-codecs",
     artifact = "org.apache.lucene:lucene-backward-codecs:" + LUCENE_VERS,
     sha1 = "a933f42e758c54c43083398127ea7342b54d8212",
 )
 
 maven_jar(
-    name = "lucene_misc",
+    name = "lucene-misc",
     artifact = "org.apache.lucene:lucene-misc:" + LUCENE_VERS,
     sha1 = "a74388857f73614e528ae44d742c60187cb55a5a",
 )
 
 maven_jar(
-    name = "lucene_queryparser",
+    name = "lucene-queryparser",
     artifact = "org.apache.lucene:lucene-queryparser:" + LUCENE_VERS,
     sha1 = "8a06fad4675473d98d93b61fea529e3f464bf69e",
 )
 
 maven_jar(
-    name = "mime_util",
+    name = "mime-util",
     artifact = "eu.medsea.mimeutil:mime-util:2.1.3",
     attach_source = False,
     sha1 = "0c9cfae15c74f62491d4f28def0dff1dabe52a47",
@@ -502,7 +502,7 @@
 PROLOG_REPO = GERRIT
 
 maven_jar(
-    name = "prolog_runtime",
+    name = "prolog-runtime",
     artifact = "com.googlecode.prolog-cafe:prolog-runtime:" + PROLOG_VERS,
     attach_source = False,
     repository = PROLOG_REPO,
@@ -510,7 +510,7 @@
 )
 
 maven_jar(
-    name = "prolog_compiler",
+    name = "prolog-compiler",
     artifact = "com.googlecode.prolog-cafe:prolog-compiler:" + PROLOG_VERS,
     attach_source = False,
     repository = PROLOG_REPO,
@@ -518,7 +518,7 @@
 )
 
 maven_jar(
-    name = "prolog_io",
+    name = "prolog-io",
     artifact = "com.googlecode.prolog-cafe:prolog-io:" + PROLOG_VERS,
     attach_source = False,
     repository = PROLOG_REPO,
@@ -534,7 +534,7 @@
 )
 
 maven_jar(
-    name = "guava_retrying",
+    name = "guava-retrying",
     artifact = "com.github.rholder:guava-retrying:2.0.0",
     sha1 = "974bc0a04a11cc4806f7c20a34703bd23c34e7f4",
 )
@@ -546,7 +546,7 @@
 )
 
 maven_jar(
-    name = "blame_cache",
+    name = "blame-cache",
     artifact = "com/google/gitiles:blame-cache:0.2-6",
     attach_source = False,
     repository = GERRIT,
@@ -561,7 +561,7 @@
 )
 
 maven_jar(
-    name = "html_types",
+    name = "html-types",
     artifact = "com.google.common.html.types:types:1.0.4",
     sha1 = "2adf4c8bfccc0ff7346f9186ac5aa57d829ad065",
 )
@@ -573,30 +573,30 @@
 )
 
 maven_jar(
-    name = "dropwizard_core",
+    name = "dropwizard-core",
     artifact = "io.dropwizard.metrics:metrics-core:4.0.2",
     sha1 = "ec9878842d510cabd6bd6a9da1bebae1ae0cd199",
 )
 
 # When updading Bouncy Castle, also update it in bazlets.
-BC_VERS = "1.57"
+BC_VERS = "1.59"
 
 maven_jar(
     name = "bcprov",
     artifact = "org.bouncycastle:bcprov-jdk15on:" + BC_VERS,
-    sha1 = "f66a135611d42c992e5745788c3f94eb06464537",
+    sha1 = "2507204241ab450456bdb8e8c0a8f986e418bd99",
 )
 
 maven_jar(
     name = "bcpg",
     artifact = "org.bouncycastle:bcpg-jdk15on:" + BC_VERS,
-    sha1 = "7b2d587f5e3780b79e1d35af3e84d00634e9420b",
+    sha1 = "ee93e5376bb6cf0a15c027b5f5e4393f2738e709",
 )
 
 maven_jar(
     name = "bcpkix",
     artifact = "org.bouncycastle:bcpkix-jdk15on:" + BC_VERS,
-    sha1 = "5c96e34bc9bd4cd6870e6d193a99438f1e274ca7",
+    sha1 = "9cef0aab8a4bb849a8476c058ce3ff302aba3fff",
 )
 
 # TODO(davido): Remove exlusion of file system provider, when this issue is fixed:
@@ -615,7 +615,7 @@
 )
 
 maven_jar(
-    name = "mina_core",
+    name = "mina-core",
     artifact = "org.apache.mina:mina-core:2.0.16",
     sha1 = "f720f17643eaa7b0fec07c1d7f6272972c02bba4",
 )
@@ -632,7 +632,7 @@
 HTTPCOMP_VERS = "4.4.1"
 
 maven_jar(
-    name = "fluent_hc",
+    name = "fluent-hc",
     artifact = "org.apache.httpcomponents:fluent-hc:" + HTTPCOMP_VERS,
     sha1 = "96fb842b68a44cc640c661186828b60590c71261",
 )
@@ -670,14 +670,14 @@
 )
 
 maven_jar(
-    name = "hamcrest_core",
+    name = "hamcrest-core",
     artifact = "org.hamcrest:hamcrest-core:1.3",
     sha1 = "42a25dc3219429f0e5d060061f71acb49bf010a0",
 )
 
 # Only needed when jgit is built from the development tree
 maven_jar(
-    name = "hamcrest_library",
+    name = "hamcrest-library",
     artifact = "org.hamcrest:hamcrest-library:1.3",
     sha1 = "4785a3c21320980282f9f33d0d1264a69040538f",
 )
@@ -716,7 +716,7 @@
 )
 
 maven_jar(
-    name = "cglib_3_2",
+    name = "cglib-3_2",
     artifact = "cglib:cglib-nodep:3.2.0",
     sha1 = "cf1ca207c15b04ace918270b6cb3f5601160cdfd",
 )
@@ -730,37 +730,37 @@
 POWERM_VERS = "1.6.1"
 
 maven_jar(
-    name = "powermock_module_junit4",
+    name = "powermock-module-junit4",
     artifact = "org.powermock:powermock-module-junit4:" + POWERM_VERS,
     sha1 = "ea8530b2848542624f110a393513af397b37b9cf",
 )
 
 maven_jar(
-    name = "powermock_module_junit4_common",
+    name = "powermock-module-junit4-common",
     artifact = "org.powermock:powermock-module-junit4-common:" + POWERM_VERS,
     sha1 = "7222ced54dabc310895d02e45c5428ca05193cda",
 )
 
 maven_jar(
-    name = "powermock_reflect",
+    name = "powermock-reflect",
     artifact = "org.powermock:powermock-reflect:" + POWERM_VERS,
     sha1 = "97d25eda8275c11161bcddda6ef8beabd534c878",
 )
 
 maven_jar(
-    name = "powermock_api_easymock",
+    name = "powermock-api-easymock",
     artifact = "org.powermock:powermock-api-easymock:" + POWERM_VERS,
     sha1 = "aa740ecf89a2f64d410b3d93ef8cd6833009ef00",
 )
 
 maven_jar(
-    name = "powermock_api_support",
+    name = "powermock-api-support",
     artifact = "org.powermock:powermock-api-support:" + POWERM_VERS,
     sha1 = "592ee6d929c324109d3469501222e0c76ccf0869",
 )
 
 maven_jar(
-    name = "powermock_core",
+    name = "powermock-core",
     artifact = "org.powermock:powermock-core:" + POWERM_VERS,
     sha1 = "5afc1efce8d44ed76b30af939657bd598e45d962",
 )
@@ -778,64 +778,64 @@
     sha1 = "df4b50061e8e4c348ce243b921f53ee63ba9bbe1",
 )
 
-JETTY_VERS = "9.4.9.v20180320"
+JETTY_VERS = "9.3.18.v20170406"
 
 maven_jar(
-    name = "jetty_servlet",
+    name = "jetty-servlet",
     artifact = "org.eclipse.jetty:jetty-servlet:" + JETTY_VERS,
-    sha1 = "d4453b746bc581af6ec5bce09228dc802bec1040",
+    sha1 = "534e7fa0e4fb6e08f89eb3f6a8c48b4f81ff5738",
 )
 
 maven_jar(
-    name = "jetty_security",
+    name = "jetty-security",
     artifact = "org.eclipse.jetty:jetty-security:" + JETTY_VERS,
-    sha1 = "dadd28ef757d9b8cdd1d7eef7fcbfa0b482c4648",
+    sha1 = "16b900e91b04511f42b706c925c8af6023d2c05e",
 )
 
 maven_jar(
-    name = "jetty_servlets",
+    name = "jetty-servlets",
     artifact = "org.eclipse.jetty:jetty-servlets:" + JETTY_VERS,
-    sha1 = "cb40696bb683655b7abb4ca72ad08708cd99ca7b",
+    sha1 = "f9311d1d8e6124d2792f4db5b29514d0ecf46812",
 )
 
 maven_jar(
-    name = "jetty_server",
+    name = "jetty-server",
     artifact = "org.eclipse.jetty:jetty-server:" + JETTY_VERS,
-    sha1 = "08847f7278e8ace7a1f5847e71563c8a10546582",
+    sha1 = "0a32feea88cba2d43951d22b60861c643454bb3f",
 )
 
 maven_jar(
-    name = "jetty_jmx",
+    name = "jetty-jmx",
     artifact = "org.eclipse.jetty:jetty-jmx:" + JETTY_VERS,
-    sha1 = "ff0978e1c74c4e08517df4d1950e61450ea987b1",
+    sha1 = "f988136dc5aa634afed6c5a35d910ee9599c6c23",
 )
 
 maven_jar(
-    name = "jetty_continuation",
+    name = "jetty-continuation",
     artifact = "org.eclipse.jetty:jetty-continuation:" + JETTY_VERS,
-    sha1 = "590a07c7daf76c755e2daefb1aa0a91b41b26d87",
+    sha1 = "3c5d89c8204d4a48a360087f95e4cbd4520b5de0",
 )
 
 maven_jar(
-    name = "jetty_http",
+    name = "jetty-http",
     artifact = "org.eclipse.jetty:jetty-http:" + JETTY_VERS,
-    sha1 = "64d93698196ea7a66b33c754a0eac2a97d5af4b6",
+    sha1 = "30ece6d732d276442d513b94d914de6fa1075fae",
 )
 
 maven_jar(
-    name = "jetty_io",
+    name = "jetty-io",
     artifact = "org.eclipse.jetty:jetty-io:" + JETTY_VERS,
-    sha1 = "938d67c72405285d2a7a6efb10d870a1b16fa2e0",
+    sha1 = "36cb411ee89be1b527b0c10747aa3153267fc3ec",
 )
 
 maven_jar(
-    name = "jetty_util",
+    name = "jetty-util",
     artifact = "org.eclipse.jetty:jetty-util:" + JETTY_VERS,
-    sha1 = "8a602b93581f6af54839728f51d51ab830bdd44d",
+    sha1 = "8600b7d028a38cb462eff338de91390b3ff5040e",
 )
 
 maven_jar(
-    name = "openid_consumer",
+    name = "openid-consumer",
     artifact = "org.openid4java:openid4java:0.9.8",
     sha1 = "de4f1b33d3b0f0b2ab1d32834ec1190b39db4160",
 )
@@ -860,26 +860,26 @@
 )
 
 maven_jar(
-    name = "codemirror_minified",
+    name = "codemirror-minified-gwt",
     artifact = "org.webjars.npm:codemirror-minified:" + CM_VERSION,
-    sha1 = "f84c178b11a188f416b4380bfb2b24f126453d28",
+    sha1 = "36558ea3b8e30782e1e09c0e7bd781e09614f139",
 )
 
 maven_jar(
-    name = "codemirror_original",
+    name = "codemirror-original-gwt",
     artifact = "org.webjars.npm:codemirror:" + CM_VERSION,
-    sha1 = "5a1f6c10d5aef0b9d2ce513dcc1e2657e4af730d",
+    sha1 = "f1f8fbbc3e2d224fdccc43d2f4180658a92320f9",
 )
 
 maven_jar(
-    name = "diff_match_patch",
+    name = "diff-match-patch",
     artifact = "org.webjars:google-diff-match-patch:" + DIFF_MATCH_PATCH_VERSION,
     attach_source = False,
     sha1 = "0cf1782dbcb8359d95070da9176059a5a9d37709",
 )
 
 maven_jar(
-    name = "commons_io",
+    name = "commons-io",
     artifact = "commons-io:commons-io:1.4",
     sha1 = "a8762d07e76cfde2395257a5da47ba7c1dbd3dce",
 )
@@ -905,7 +905,7 @@
 JACKSON_VERSION = "2.8.9"
 
 maven_jar(
-    name = "jackson_core",
+    name = "jackson-core",
     artifact = "com.fasterxml.jackson.core:jackson-core:" + JACKSON_VERSION,
     sha1 = "569b1752705da98f49aabe2911cc956ff7d8ed9d",
 )
@@ -917,7 +917,7 @@
 )
 
 maven_jar(
-    name = "httpcore_nio",
+    name = "httpcore-nio",
     artifact = "org.apache.httpcomponents:httpcore-nio:" + HTTPCOMP_VERS,
     sha1 = "a8c5e3c3bfea5ce23fb647c335897e415eb442e3",
 )
@@ -929,13 +929,13 @@
 )
 
 maven_jar(
-    name = "duct_tape",
+    name = "duct-tape",
     artifact = "org.rnorth.duct-tape:duct-tape:1.0.7",
     sha1 = "a26b5d90d88c91321dc7a3734ea72d2fc019ebb6",
 )
 
 maven_jar(
-    name = "visible_assertions",
+    name = "visible-assertions",
     artifact = "org.rnorth.visible-assertions:visible-assertions:2.1.0",
     sha1 = "f2fcff2862860828ac38a5e1f14d941787c06b13",
 )
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.java
index 9799723..0b32cd5 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.java
@@ -129,6 +129,8 @@
 
   String buttonGeneratePassword();
 
+  String revokePassword();
+
   String linkObtainPassword();
 
   String linkEditFullName();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.properties
index ca7cc27..4b01513 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.properties
@@ -74,6 +74,7 @@
 confirmSetUserName = Setting the Username is permanent.  Are you sure?
 buttonClearPassword = Clear Password
 buttonGeneratePassword = Generate Password
+revokePassword = (click 'Generate Password' to revoke an old password)
 linkObtainPassword = Obtain Password
 linkEditFullName = Edit
 linkReloadContact = Reload
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyPasswordScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyPasswordScreen.java
index 3852387..5dd7530 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyPasswordScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyPasswordScreen.java
@@ -49,7 +49,7 @@
       return;
     }
 
-    password = new CopyableLabel("(click 'generate' to revoke an old password)");
+    password = new CopyableLabel(Util.C.revokePassword());
     password.addStyleName(Gerrit.RESOURCES.css().accountPassword());
 
     generatePassword = new Button(Util.C.buttonGeneratePassword());
diff --git a/gerrit-plugin-gwtui/BUILD b/gerrit-plugin-gwtui/BUILD
index 0880993..bfd977d 100644
--- a/gerrit-plugin-gwtui/BUILD
+++ b/gerrit-plugin-gwtui/BUILD
@@ -67,7 +67,7 @@
     libs = DEPS + [
         ":gwtui-api-lib",
         "//lib:gwtjsonrpc",
-        "//lib:gwtorm_client",
+        "//lib:gwtorm-client",
         "//lib/gwt:dev",
         "//gerrit-gwtui-common:client-lib",
         "//java/com/google/gerrit/common:client",
diff --git a/java/com/google/gerrit/acceptance/BUILD b/java/com/google/gerrit/acceptance/BUILD
index 770805b..25e1d7c 100644
--- a/java/com/google/gerrit/acceptance/BUILD
+++ b/java/com/google/gerrit/acceptance/BUILD
@@ -85,7 +85,7 @@
         "//lib/httpcomponents:httpcore",
         "//lib/jetty:servlet",
         "//lib/jgit/org.eclipse.jgit.junit:junit",
-        "//lib/log:impl_log4j",
+        "//lib/log:impl-log4j",
         "//lib/log:log4j",
         "//lib/truth",
         "//lib/truth:truth-java8-extension",
diff --git a/java/com/google/gerrit/common/BUILD b/java/com/google/gerrit/common/BUILD
index 800a975..2122ebb 100644
--- a/java/com/google/gerrit/common/BUILD
+++ b/java/com/google/gerrit/common/BUILD
@@ -20,7 +20,7 @@
         "//java/com/google/gerrit/extensions:api",
         "//java/com/google/gerrit/prettify:client",
         "//lib:guava",
-        "//lib:gwtorm_client",
+        "//lib:gwtorm-client",
         "//lib:servlet-api-3_1",
         "//lib/auto:auto-value",
         "//lib/auto:auto-value-annotations",
diff --git a/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java b/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java
index 0ccd820..3755faa 100644
--- a/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java
+++ b/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java
@@ -118,7 +118,8 @@
       SitePaths sitePaths,
       Schema<V> schema,
       ElasticRestClientProvider client,
-      String indexName) {
+      String indexName,
+      String indexType) {
     this.sitePaths = sitePaths;
     this.schema = schema;
     this.gson = new GsonBuilder().setFieldNamingPolicy(LOWER_CASE_WITH_UNDERSCORES).create();
@@ -126,7 +127,16 @@
     this.indexName = cfg.getIndexName(indexName, schema.getVersion());
     this.indexNameRaw = indexName;
     this.client = client;
-    this.type = client.adapter().getType(indexName);
+    this.type = client.adapter().getType(indexType);
+  }
+
+  AbstractElasticIndex(
+      ElasticConfiguration cfg,
+      SitePaths sitePaths,
+      Schema<V> schema,
+      ElasticRestClientProvider client,
+      String indexName) {
+    this(cfg, sitePaths, schema, client, indexName, indexName);
   }
 
   @Override
diff --git a/java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java b/java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java
index 58f4fb9..d18af42 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java
@@ -46,14 +46,14 @@
 public class ElasticAccountIndex extends AbstractElasticIndex<Account.Id, AccountState>
     implements AccountIndex {
   static class AccountMapping {
-    MappingProperties accounts;
+    final MappingProperties accounts;
 
     AccountMapping(Schema<AccountState> schema, ElasticQueryAdapter adapter) {
       this.accounts = ElasticMapping.createMapping(schema, adapter);
     }
   }
 
-  static final String ACCOUNTS = "accounts";
+  private static final String ACCOUNTS = "accounts";
 
   private final AccountMapping mapping;
   private final Provider<AccountCache> accountCache;
diff --git a/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java b/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java
index 1ec8d2b..f6af79f 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java
@@ -76,9 +76,9 @@
 class ElasticChangeIndex extends AbstractElasticIndex<Change.Id, ChangeData>
     implements ChangeIndex {
   static class ChangeMapping {
-    MappingProperties changes;
-    MappingProperties openChanges;
-    MappingProperties closedChanges;
+    final MappingProperties changes;
+    final MappingProperties openChanges;
+    final MappingProperties closedChanges;
 
     ChangeMapping(Schema<ChangeData> schema, ElasticQueryAdapter adapter) {
       MappingProperties mapping = ElasticMapping.createMapping(schema, adapter);
@@ -88,9 +88,9 @@
     }
   }
 
-  static final String CHANGES = "changes";
-  static final String OPEN_CHANGES = "open_" + CHANGES;
-  static final String CLOSED_CHANGES = "closed_" + CHANGES;
+  private static final String CHANGES = "changes";
+  private static final String OPEN_CHANGES = "open_" + CHANGES;
+  private static final String CLOSED_CHANGES = "closed_" + CHANGES;
 
   private final ChangeMapping mapping;
   private final Provider<ReviewDb> db;
diff --git a/java/com/google/gerrit/elasticsearch/ElasticConfiguration.java b/java/com/google/gerrit/elasticsearch/ElasticConfiguration.java
index 84dae7f..4184ec0 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticConfiguration.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticConfiguration.java
@@ -80,11 +80,11 @@
     }
   }
 
-  public Config getConfig() {
+  Config getConfig() {
     return cfg;
   }
 
-  public String getIndexName(String name, int schemaVersion) {
+  String getIndexName(String name, int schemaVersion) {
     return String.format("%s%s_%04d", prefix, name, schemaVersion);
   }
 
diff --git a/java/com/google/gerrit/elasticsearch/ElasticGroupIndex.java b/java/com/google/gerrit/elasticsearch/ElasticGroupIndex.java
index cf1a4ed..bf6b962 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticGroupIndex.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticGroupIndex.java
@@ -44,14 +44,14 @@
 public class ElasticGroupIndex extends AbstractElasticIndex<AccountGroup.UUID, InternalGroup>
     implements GroupIndex {
   static class GroupMapping {
-    MappingProperties groups;
+    final MappingProperties groups;
 
     GroupMapping(Schema<InternalGroup> schema, ElasticQueryAdapter adapter) {
       this.groups = ElasticMapping.createMapping(schema, adapter);
     }
   }
 
-  static final String GROUPS = "groups";
+  private static final String GROUPS = "groups";
 
   private final GroupMapping mapping;
   private final Provider<GroupCache> groupCache;
diff --git a/java/com/google/gerrit/elasticsearch/ElasticIndexVersionManager.java b/java/com/google/gerrit/elasticsearch/ElasticIndexVersionManager.java
index 58272f7..11d21dc 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticIndexVersionManager.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticIndexVersionManager.java
@@ -63,7 +63,7 @@
           logger.atWarning().log("Unrecognized version in index %s: %s", def.getName(), version);
           continue;
         }
-        versions.put(v, new Version<V>(null, v, true, cfg.getReady(def.getName(), v)));
+        versions.put(v, new Version<>(null, v, true, cfg.getReady(def.getName(), v)));
       }
     } catch (IOException e) {
       logger.atSevere().withCause(e).log("Error scanning index: %s", def.getName());
diff --git a/java/com/google/gerrit/elasticsearch/ElasticQueryBuilder.java b/java/com/google/gerrit/elasticsearch/ElasticQueryBuilder.java
index 2a97e2e..394158d 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticQueryBuilder.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticQueryBuilder.java
@@ -34,7 +34,7 @@
 
 public class ElasticQueryBuilder {
 
-  protected <T> QueryBuilder toQueryBuilder(Predicate<T> p) throws QueryParseException {
+  <T> QueryBuilder toQueryBuilder(Predicate<T> p) throws QueryParseException {
     if (p instanceof AndPredicate) {
       return and(p);
     } else if (p instanceof OrPredicate) {
diff --git a/java/com/google/gerrit/elasticsearch/ElasticVersion.java b/java/com/google/gerrit/elasticsearch/ElasticVersion.java
index ff26382..b65eb31 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticVersion.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticVersion.java
@@ -25,7 +25,7 @@
   private final String version;
   private final Pattern pattern;
 
-  private ElasticVersion(String version) {
+  ElasticVersion(String version) {
     this.version = version;
     this.pattern = Pattern.compile(version);
   }
diff --git a/java/com/google/gerrit/httpd/BUILD b/java/com/google/gerrit/httpd/BUILD
index 4bd3e2e..bbb5b66 100644
--- a/java/com/google/gerrit/httpd/BUILD
+++ b/java/com/google/gerrit/httpd/BUILD
@@ -18,8 +18,6 @@
         "//java/com/google/gerrit/server/restapi",
         "//java/com/google/gerrit/util/cli",
         "//java/com/google/gerrit/util/http",
-        "//java/com/google/gwtexpui/linker:server",
-        "//java/com/google/gwtexpui/server",
         "//java/org/eclipse/jgit:server",
         "//lib:args4j",
         "//lib:gson",
diff --git a/java/com/google/gwtexpui/server/CacheControlFilter.java b/java/com/google/gerrit/httpd/GwtCacheControlFilter.java
similarity index 94%
rename from java/com/google/gwtexpui/server/CacheControlFilter.java
rename to java/com/google/gerrit/httpd/GwtCacheControlFilter.java
index 571f72d..5ac3d2f 100644
--- a/java/com/google/gwtexpui/server/CacheControlFilter.java
+++ b/java/com/google/gerrit/httpd/GwtCacheControlFilter.java
@@ -12,8 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gwtexpui.server;
+package com.google.gerrit.httpd;
 
+import com.google.gerrit.util.http.CacheHeaders;
+import com.google.inject.Singleton;
 import java.io.IOException;
 import java.util.concurrent.TimeUnit;
 import javax.servlet.Filter;
@@ -46,7 +48,8 @@
  *   &lt;/filter-mapping&gt;
  * </pre>
  */
-public class CacheControlFilter implements Filter {
+@Singleton
+class GwtCacheControlFilter implements Filter {
   @Override
   public void init(FilterConfig config) {}
 
diff --git a/java/com/google/gerrit/httpd/UrlModule.java b/java/com/google/gerrit/httpd/UrlModule.java
index 6210385..1702a38 100644
--- a/java/com/google/gerrit/httpd/UrlModule.java
+++ b/java/com/google/gerrit/httpd/UrlModule.java
@@ -34,7 +34,6 @@
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.config.AuthConfig;
 import com.google.gerrit.server.config.GerritOptions;
-import com.google.gwtexpui.server.CacheControlFilter;
 import com.google.inject.Key;
 import com.google.inject.Provider;
 import com.google.inject.internal.UniqueAnnotations;
@@ -56,8 +55,7 @@
 
   @Override
   protected void configureServlets() {
-    filter("/*").through(Key.get(CacheControlFilter.class));
-    bind(Key.get(CacheControlFilter.class)).in(SINGLETON);
+    filter("/*").through(GwtCacheControlFilter.class);
 
     if (options.enableGwtUi()) {
       filter("/").through(XsrfCookieFilter.class);
diff --git a/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java b/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java
index 77c79bb..ea01809 100644
--- a/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java
+++ b/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java
@@ -34,7 +34,7 @@
 import com.google.gerrit.server.account.AuthResult;
 import com.google.gerrit.server.account.externalids.ExternalId;
 import com.google.gerrit.server.query.account.InternalAccountQuery;
-import com.google.gwtexpui.server.CacheHeaders;
+import com.google.gerrit.util.http.CacheHeaders;
 import com.google.gwtorm.server.OrmException;
 import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
diff --git a/java/com/google/gerrit/httpd/auth/container/HttpAuthFilter.java b/java/com/google/gerrit/httpd/auth/container/HttpAuthFilter.java
index c7229bc..0b3c29d 100644
--- a/java/com/google/gerrit/httpd/auth/container/HttpAuthFilter.java
+++ b/java/com/google/gerrit/httpd/auth/container/HttpAuthFilter.java
@@ -28,7 +28,7 @@
 import com.google.gerrit.httpd.raw.HostPageServlet;
 import com.google.gerrit.server.account.externalids.ExternalId;
 import com.google.gerrit.server.config.AuthConfig;
-import com.google.gwtexpui.server.CacheHeaders;
+import com.google.gerrit.util.http.CacheHeaders;
 import com.google.gwtjsonrpc.server.RPCServletUtils;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
diff --git a/java/com/google/gerrit/httpd/auth/container/HttpLoginServlet.java b/java/com/google/gerrit/httpd/auth/container/HttpLoginServlet.java
index 6340b22..fd2f628 100644
--- a/java/com/google/gerrit/httpd/auth/container/HttpLoginServlet.java
+++ b/java/com/google/gerrit/httpd/auth/container/HttpLoginServlet.java
@@ -30,7 +30,7 @@
 import com.google.gerrit.server.account.AuthResult;
 import com.google.gerrit.server.account.externalids.ExternalId;
 import com.google.gerrit.server.config.AuthConfig;
-import com.google.gwtexpui.server.CacheHeaders;
+import com.google.gerrit.util.http.CacheHeaders;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
diff --git a/java/com/google/gerrit/httpd/auth/container/HttpsClientSslCertLoginServlet.java b/java/com/google/gerrit/httpd/auth/container/HttpsClientSslCertLoginServlet.java
index e93b0b6..f21c96e 100644
--- a/java/com/google/gerrit/httpd/auth/container/HttpsClientSslCertLoginServlet.java
+++ b/java/com/google/gerrit/httpd/auth/container/HttpsClientSslCertLoginServlet.java
@@ -17,7 +17,7 @@
 import com.google.gerrit.common.Nullable;
 import com.google.gerrit.httpd.LoginUrlToken;
 import com.google.gerrit.server.config.CanonicalWebUrl;
-import com.google.gwtexpui.server.CacheHeaders;
+import com.google.gerrit.util.http.CacheHeaders;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
diff --git a/java/com/google/gerrit/httpd/auth/ldap/LdapLoginServlet.java b/java/com/google/gerrit/httpd/auth/ldap/LdapLoginServlet.java
index 6370476..116ad6d 100644
--- a/java/com/google/gerrit/httpd/auth/ldap/LdapLoginServlet.java
+++ b/java/com/google/gerrit/httpd/auth/ldap/LdapLoginServlet.java
@@ -33,7 +33,7 @@
 import com.google.gerrit.server.account.AuthResult;
 import com.google.gerrit.server.account.AuthenticationFailedException;
 import com.google.gerrit.server.auth.AuthenticationUnavailableException;
-import com.google.gwtexpui.server.CacheHeaders;
+import com.google.gerrit.util.http.CacheHeaders;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import java.io.IOException;
diff --git a/java/com/google/gerrit/httpd/auth/openid/BUILD b/java/com/google/gerrit/httpd/auth/openid/BUILD
index 9c48832..bfb2551 100644
--- a/java/com/google/gerrit/httpd/auth/openid/BUILD
+++ b/java/com/google/gerrit/httpd/auth/openid/BUILD
@@ -11,7 +11,7 @@
         "//java/com/google/gerrit/extensions:api",
         "//java/com/google/gerrit/httpd",
         "//java/com/google/gerrit/reviewdb:server",
-        "//java/com/google/gwtexpui/server",
+        "//java/com/google/gerrit/util/http",
         "//java/com/google/gerrit/server",
         "//lib:guava",
         "//lib:gwtorm",
diff --git a/java/com/google/gerrit/httpd/auth/openid/OpenIdLoginServlet.java b/java/com/google/gerrit/httpd/auth/openid/OpenIdLoginServlet.java
index a97e8ae..23cf468 100644
--- a/java/com/google/gerrit/httpd/auth/openid/OpenIdLoginServlet.java
+++ b/java/com/google/gerrit/httpd/auth/openid/OpenIdLoginServlet.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.httpd.auth.openid;
 
-import com.google.gwtexpui.server.CacheHeaders;
+import com.google.gerrit.util.http.CacheHeaders;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import java.io.IOException;
diff --git a/java/com/google/gerrit/httpd/gitweb/GitLogoServlet.java b/java/com/google/gerrit/httpd/gitweb/GitLogoServlet.java
index af853cc..d57e629 100644
--- a/java/com/google/gerrit/httpd/gitweb/GitLogoServlet.java
+++ b/java/com/google/gerrit/httpd/gitweb/GitLogoServlet.java
@@ -18,7 +18,7 @@
 
 import com.google.common.io.ByteStreams;
 import com.google.gerrit.server.config.GitwebCgiConfig;
-import com.google.gwtexpui.server.CacheHeaders;
+import com.google.gerrit.util.http.CacheHeaders;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import java.io.IOException;
diff --git a/java/com/google/gerrit/httpd/gitweb/GitwebCssServlet.java b/java/com/google/gerrit/httpd/gitweb/GitwebCssServlet.java
index 5e22081..feee3ba 100644
--- a/java/com/google/gerrit/httpd/gitweb/GitwebCssServlet.java
+++ b/java/com/google/gerrit/httpd/gitweb/GitwebCssServlet.java
@@ -20,7 +20,7 @@
 import com.google.gerrit.httpd.HtmlDomUtil;
 import com.google.gerrit.server.config.GitwebCgiConfig;
 import com.google.gerrit.server.config.SitePaths;
-import com.google.gwtexpui.server.CacheHeaders;
+import com.google.gerrit.util.http.CacheHeaders;
 import com.google.gwtjsonrpc.server.RPCServletUtils;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
diff --git a/java/com/google/gerrit/httpd/gitweb/GitwebJavaScriptServlet.java b/java/com/google/gerrit/httpd/gitweb/GitwebJavaScriptServlet.java
index 651b582..82dd901 100644
--- a/java/com/google/gerrit/httpd/gitweb/GitwebJavaScriptServlet.java
+++ b/java/com/google/gerrit/httpd/gitweb/GitwebJavaScriptServlet.java
@@ -18,7 +18,7 @@
 
 import com.google.common.io.ByteStreams;
 import com.google.gerrit.server.config.GitwebCgiConfig;
-import com.google.gwtexpui.server.CacheHeaders;
+import com.google.gerrit.util.http.CacheHeaders;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import java.io.IOException;
diff --git a/java/com/google/gerrit/httpd/gitweb/GitwebServlet.java b/java/com/google/gerrit/httpd/gitweb/GitwebServlet.java
index 383efd3..5e59c9a 100644
--- a/java/com/google/gerrit/httpd/gitweb/GitwebServlet.java
+++ b/java/com/google/gerrit/httpd/gitweb/GitwebServlet.java
@@ -55,7 +55,7 @@
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.project.ProjectState;
 import com.google.gerrit.server.ssh.SshInfo;
-import com.google.gwtexpui.server.CacheHeaders;
+import com.google.gerrit.util.http.CacheHeaders;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.ProvisionException;
diff --git a/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java b/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java
index 63ce211..9a24e47 100644
--- a/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java
+++ b/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java
@@ -52,8 +52,8 @@
 import com.google.gerrit.server.plugins.ReloadPluginListener;
 import com.google.gerrit.server.plugins.StartPluginListener;
 import com.google.gerrit.server.ssh.SshInfo;
+import com.google.gerrit.util.http.CacheHeaders;
 import com.google.gerrit.util.http.RequestUtil;
-import com.google.gwtexpui.server.CacheHeaders;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
diff --git a/java/com/google/gerrit/httpd/plugins/LfsPluginServlet.java b/java/com/google/gerrit/httpd/plugins/LfsPluginServlet.java
index 0ee22fa..67ee3ba 100644
--- a/java/com/google/gerrit/httpd/plugins/LfsPluginServlet.java
+++ b/java/com/google/gerrit/httpd/plugins/LfsPluginServlet.java
@@ -25,7 +25,7 @@
 import com.google.gerrit.server.plugins.Plugin;
 import com.google.gerrit.server.plugins.ReloadPluginListener;
 import com.google.gerrit.server.plugins.StartPluginListener;
-import com.google.gwtexpui.server.CacheHeaders;
+import com.google.gerrit.util.http.CacheHeaders;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import com.google.inject.servlet.GuiceFilter;
diff --git a/java/com/google/gerrit/httpd/raw/BazelBuild.java b/java/com/google/gerrit/httpd/raw/BazelBuild.java
index 92a5aaa..940a51b 100644
--- a/java/com/google/gerrit/httpd/raw/BazelBuild.java
+++ b/java/com/google/gerrit/httpd/raw/BazelBuild.java
@@ -23,7 +23,7 @@
 import com.google.common.html.HtmlEscapers;
 import com.google.common.io.ByteStreams;
 import com.google.gerrit.common.TimeUtil;
-import com.google.gwtexpui.server.CacheHeaders;
+import com.google.gerrit.util.http.CacheHeaders;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InterruptedIOException;
diff --git a/java/com/google/gerrit/httpd/raw/HostPageServlet.java b/java/com/google/gerrit/httpd/raw/HostPageServlet.java
index 74868d7..160732e 100644
--- a/java/com/google/gerrit/httpd/raw/HostPageServlet.java
+++ b/java/com/google/gerrit/httpd/raw/HostPageServlet.java
@@ -39,7 +39,7 @@
 import com.google.gerrit.server.notedb.NotesMigration;
 import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.gerrit.server.restapi.account.GetDiffPreferences;
-import com.google.gwtexpui.server.CacheHeaders;
+import com.google.gerrit.util.http.CacheHeaders;
 import com.google.gwtjsonrpc.server.JsonServlet;
 import com.google.gwtjsonrpc.server.RPCServletUtils;
 import com.google.inject.Inject;
diff --git a/java/com/google/gerrit/httpd/raw/LegacyGerritServlet.java b/java/com/google/gerrit/httpd/raw/LegacyGerritServlet.java
index 10735a5..e12f0a5 100644
--- a/java/com/google/gerrit/httpd/raw/LegacyGerritServlet.java
+++ b/java/com/google/gerrit/httpd/raw/LegacyGerritServlet.java
@@ -15,7 +15,7 @@
 package com.google.gerrit.httpd.raw;
 
 import com.google.gerrit.httpd.HtmlDomUtil;
-import com.google.gwtexpui.server.CacheHeaders;
+import com.google.gerrit.util.http.CacheHeaders;
 import com.google.gwtjsonrpc.server.RPCServletUtils;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
diff --git a/java/com/google/gerrit/httpd/raw/RecompileGwtUiFilter.java b/java/com/google/gerrit/httpd/raw/RecompileGwtUiFilter.java
index 90aedbe..c6c3367 100644
--- a/java/com/google/gerrit/httpd/raw/RecompileGwtUiFilter.java
+++ b/java/com/google/gerrit/httpd/raw/RecompileGwtUiFilter.java
@@ -14,7 +14,6 @@
 
 package com.google.gerrit.httpd.raw;
 
-import com.google.gwtexpui.linker.server.UserAgentRule;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
diff --git a/java/com/google/gerrit/httpd/raw/ResourceServlet.java b/java/com/google/gerrit/httpd/raw/ResourceServlet.java
index 035653d..64b5bbb 100644
--- a/java/com/google/gerrit/httpd/raw/ResourceServlet.java
+++ b/java/com/google/gerrit/httpd/raw/ResourceServlet.java
@@ -34,7 +34,7 @@
 import com.google.common.hash.Hashing;
 import com.google.gerrit.common.Nullable;
 import com.google.gerrit.httpd.HtmlDomUtil;
-import com.google.gwtexpui.server.CacheHeaders;
+import com.google.gerrit.util.http.CacheHeaders;
 import com.google.gwtjsonrpc.server.RPCServletUtils;
 import java.io.IOException;
 import java.io.OutputStream;
diff --git a/java/com/google/gerrit/httpd/raw/SshInfoServlet.java b/java/com/google/gerrit/httpd/raw/SshInfoServlet.java
index 55bc2a6..1d1fe6cc 100644
--- a/java/com/google/gerrit/httpd/raw/SshInfoServlet.java
+++ b/java/com/google/gerrit/httpd/raw/SshInfoServlet.java
@@ -17,7 +17,7 @@
 import static java.nio.charset.StandardCharsets.UTF_8;
 
 import com.google.gerrit.server.ssh.SshInfo;
-import com.google.gwtexpui.server.CacheHeaders;
+import com.google.gerrit.util.http.CacheHeaders;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import com.jcraft.jsch.HostKey;
diff --git a/java/com/google/gwtexpui/linker/server/UserAgentRule.java b/java/com/google/gerrit/httpd/raw/UserAgentRule.java
similarity index 93%
rename from java/com/google/gwtexpui/linker/server/UserAgentRule.java
rename to java/com/google/gerrit/httpd/raw/UserAgentRule.java
index 8f7bede..4aac243 100644
--- a/java/com/google/gwtexpui/linker/server/UserAgentRule.java
+++ b/java/com/google/gerrit/httpd/raw/UserAgentRule.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gwtexpui.linker.server;
+package com.google.gerrit.httpd.raw;
 
 import static java.util.regex.Pattern.compile;
 
@@ -28,15 +28,15 @@
  *
  * <p>Ported from JavaScript in {@code com.google.gwt.user.UserAgent.gwt.xml}.
  */
-public class UserAgentRule {
+class UserAgentRule {
   private static final Pattern msie = compile(".*msie ([0-11]+)\\.([0-11]+).*");
   private static final Pattern gecko = compile(".*rv:([0-9]+)\\.([0-9]+).*");
 
-  public String getName() {
+  String getName() {
     return "user.agent";
   }
 
-  public String select(HttpServletRequest req) {
+  String select(HttpServletRequest req) {
     String ua = req.getHeader("User-Agent");
     if (ua == null) {
       return null;
diff --git a/java/com/google/gerrit/httpd/resources/Resource.java b/java/com/google/gerrit/httpd/resources/Resource.java
index bfa0b95..878912e 100644
--- a/java/com/google/gerrit/httpd/resources/Resource.java
+++ b/java/com/google/gerrit/httpd/resources/Resource.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.httpd.resources;
 
-import com.google.gwtexpui.server.CacheHeaders;
+import com.google.gerrit.util.http.CacheHeaders;
 import java.io.IOException;
 import java.io.Serializable;
 import javax.servlet.http.HttpServletRequest;
diff --git a/java/com/google/gerrit/httpd/restapi/ParameterParser.java b/java/com/google/gerrit/httpd/restapi/ParameterParser.java
index bfaf0c7..2870cd0 100644
--- a/java/com/google/gerrit/httpd/restapi/ParameterParser.java
+++ b/java/com/google/gerrit/httpd/restapi/ParameterParser.java
@@ -38,11 +38,11 @@
 import com.google.gerrit.extensions.restapi.Url;
 import com.google.gerrit.server.DynamicOptions;
 import com.google.gerrit.util.cli.CmdLineParser;
+import com.google.gerrit.util.http.CacheHeaders;
 import com.google.gson.JsonArray;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonPrimitive;
-import com.google.gwtexpui.server.CacheHeaders;
 import com.google.inject.Inject;
 import com.google.inject.Injector;
 import java.io.IOException;
diff --git a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
index 4c9a035..546bb9f 100644
--- a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
+++ b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
@@ -110,6 +110,7 @@
 import com.google.gerrit.server.permissions.PermissionBackend;
 import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.gerrit.server.update.UpdateException;
+import com.google.gerrit.util.http.CacheHeaders;
 import com.google.gerrit.util.http.RequestUtil;
 import com.google.gson.ExclusionStrategy;
 import com.google.gson.FieldAttributes;
@@ -123,7 +124,6 @@
 import com.google.gson.stream.JsonToken;
 import com.google.gson.stream.JsonWriter;
 import com.google.gson.stream.MalformedJsonException;
-import com.google.gwtexpui.server.CacheHeaders;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.TypeLiteral;
@@ -846,16 +846,25 @@
     throw new BadRequestException("Expected JSON object");
   }
 
+  @SuppressWarnings("unchecked")
   private static Object createInstance(Type type)
       throws NoSuchMethodException, InstantiationException, IllegalAccessException,
           InvocationTargetException {
     if (type instanceof Class) {
-      @SuppressWarnings("unchecked")
       Class<Object> clazz = (Class<Object>) type;
       Constructor<Object> c = clazz.getDeclaredConstructor();
       c.setAccessible(true);
       return c.newInstance();
     }
+    if (type instanceof ParameterizedType) {
+      Type rawType = ((ParameterizedType) type).getRawType();
+      if (rawType instanceof Class && List.class.isAssignableFrom((Class<Object>) rawType)) {
+        return new ArrayList<>();
+      }
+      if (rawType instanceof Class && Map.class.isAssignableFrom((Class<Object>) rawType)) {
+        return new HashMap<>();
+      }
+    }
     throw new InstantiationException("Cannot make " + type);
   }
 
diff --git a/java/com/google/gerrit/index/BUILD b/java/com/google/gerrit/index/BUILD
index 5074350..2442b593 100644
--- a/java/com/google/gerrit/index/BUILD
+++ b/java/com/google/gerrit/index/BUILD
@@ -20,7 +20,7 @@
     ],
     deps = [
         ":query_exception",
-        "//lib/antlr:java_runtime",
+        "//lib/antlr:java-runtime",
     ],
 )
 
@@ -40,7 +40,7 @@
         "//lib:guava",
         "//lib:gwtjsonrpc",
         "//lib:gwtorm",
-        "//lib/antlr:java_runtime",
+        "//lib/antlr:java-runtime",
         "//lib/auto:auto-value",
         "//lib/auto:auto-value-annotations",
         "//lib/flogger:api",
diff --git a/java/com/google/gerrit/pgm/BUILD b/java/com/google/gerrit/pgm/BUILD
index c83f8af..95570ec 100644
--- a/java/com/google/gerrit/pgm/BUILD
+++ b/java/com/google/gerrit/pgm/BUILD
@@ -42,8 +42,7 @@
         "//java/com/google/gerrit/server/restapi",
         "//java/com/google/gerrit/server/schema",
         "//java/com/google/gerrit/sshd",
-        "//java/com/google/gwtexpui/linker:server",
-        "//java/com/google/gwtexpui/server",
+        "//java/com/google/gerrit/util/http",
         "//lib:args4j",
         "//lib:guava",
         "//lib:gwtorm",
diff --git a/java/com/google/gerrit/pgm/http/jetty/BUILD b/java/com/google/gerrit/pgm/http/jetty/BUILD
index 6dc63658..b1da011 100644
--- a/java/com/google/gerrit/pgm/http/jetty/BUILD
+++ b/java/com/google/gerrit/pgm/http/jetty/BUILD
@@ -10,7 +10,7 @@
         "//java/com/google/gerrit/lifecycle",
         "//java/com/google/gerrit/server",
         "//java/com/google/gerrit/sshd",
-        "//java/com/google/gwtexpui/server",
+        "//java/com/google/gerrit/util/http",
         "//lib:guava",
         "//lib:servlet-api-3_1",
         "//lib/flogger:api",
diff --git a/java/com/google/gerrit/pgm/http/jetty/HiddenErrorHandler.java b/java/com/google/gerrit/pgm/http/jetty/HiddenErrorHandler.java
index 9347171..1c43240 100644
--- a/java/com/google/gerrit/pgm/http/jetty/HiddenErrorHandler.java
+++ b/java/com/google/gerrit/pgm/http/jetty/HiddenErrorHandler.java
@@ -18,7 +18,7 @@
 
 import com.google.common.base.Strings;
 import com.google.common.flogger.FluentLogger;
-import com.google.gwtexpui.server.CacheHeaders;
+import com.google.gerrit.util.http.CacheHeaders;
 import java.io.IOException;
 import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletRequest;
diff --git a/java/com/google/gerrit/pgm/http/jetty/ProjectQoSFilter.java b/java/com/google/gerrit/pgm/http/jetty/ProjectQoSFilter.java
index 9354209..96cf7be 100644
--- a/java/com/google/gerrit/pgm/http/jetty/ProjectQoSFilter.java
+++ b/java/com/google/gerrit/pgm/http/jetty/ProjectQoSFilter.java
@@ -61,7 +61,6 @@
  * Jetty's HTTP parser to crash, so we instead block the SSH execution queue thread and ask Jetty to
  * resume processing on the web service thread.
  */
-@SuppressWarnings("deprecation")
 @Singleton
 public class ProjectQoSFilter implements Filter {
   private static final String ATT_SPACE = ProjectQoSFilter.class.getName();
diff --git a/java/com/google/gerrit/reviewdb/BUILD b/java/com/google/gerrit/reviewdb/BUILD
index 6f6b9a6..40f39c0 100644
--- a/java/com/google/gerrit/reviewdb/BUILD
+++ b/java/com/google/gerrit/reviewdb/BUILD
@@ -10,8 +10,8 @@
     gwt_xml = "ReviewDB.gwt.xml",
     deps = [
         "//java/com/google/gerrit/extensions:client",
-        "//lib:gwtorm_client",
-        "//lib:gwtorm_client_src",
+        "//lib:gwtorm-client",
+        "//lib:gwtorm-client_src",
     ],
 )
 
diff --git a/java/com/google/gerrit/server/ChangeUtil.java b/java/com/google/gerrit/server/ChangeUtil.java
index 56359ce..d90f5d0 100644
--- a/java/com/google/gerrit/server/ChangeUtil.java
+++ b/java/com/google/gerrit/server/ChangeUtil.java
@@ -45,7 +45,7 @@
       Ordering.from(comparingInt(PatchSet::getPatchSetId));
 
   public static String formatChangeUrl(String canonicalWebUrl, Change change) {
-    return canonicalWebUrl + "#/c/" + change.getProject().get() + "/+/" + change.getChangeId();
+    return canonicalWebUrl + "c/" + change.getProject().get() + "/+/" + change.getChangeId();
   }
 
   /** @return a new unique identifier for change message entities. */
diff --git a/java/com/google/gerrit/server/StarredChangesUtil.java b/java/com/google/gerrit/server/StarredChangesUtil.java
index 0d8d7c1..0fbf200 100644
--- a/java/com/google/gerrit/server/StarredChangesUtil.java
+++ b/java/com/google/gerrit/server/StarredChangesUtil.java
@@ -476,6 +476,11 @@
 
   private void deleteRef(Repository repo, String refName, ObjectId oldObjectId)
       throws IOException, OrmException {
+    if (ObjectId.zeroId().equals(oldObjectId)) {
+      // ref doesn't exist
+      return;
+    }
+
     RefUpdate u = repo.updateRef(refName);
     u.setForceUpdate(true);
     u.setExpectedOldObjectId(oldObjectId);
diff --git a/java/com/google/gerrit/server/cache/PerThreadCache.java b/java/com/google/gerrit/server/cache/PerThreadCache.java
index 0881d59..b4f79d1 100644
--- a/java/com/google/gerrit/server/cache/PerThreadCache.java
+++ b/java/com/google/gerrit/server/cache/PerThreadCache.java
@@ -51,11 +51,11 @@
 public class PerThreadCache implements AutoCloseable {
   private static final ThreadLocal<PerThreadCache> CACHE = new ThreadLocal<>();
   /**
-   * Cache at maximum 50 values per thread. This value was chosen arbitrarily. Some endpoints (like
+   * Cache at maximum 25 values per thread. This value was chosen arbitrarily. Some endpoints (like
    * ListProjects) break the assumption that the data cached in a request is limited. To prevent
    * this class from accumulating an unbound number of objects, we enforce this limit.
    */
-  private static final int PER_THREAD_CACHE_SIZE = 50;
+  private static final int PER_THREAD_CACHE_SIZE = 25;
 
   /**
    * Unique key for key-value mappings stored in PerThreadCache. The key is based on the value's
diff --git a/java/com/google/gerrit/server/change/ActionJson.java b/java/com/google/gerrit/server/change/ActionJson.java
index 8879235..fbabdd5 100644
--- a/java/com/google/gerrit/server/change/ActionJson.java
+++ b/java/com/google/gerrit/server/change/ActionJson.java
@@ -139,6 +139,7 @@
     copy.stars = changeInfo.stars;
     copy.submitted = changeInfo.submitted;
     copy.submitter = changeInfo.submitter;
+    copy.workInProgress = changeInfo.workInProgress;
     copy.id = changeInfo.id;
     return copy;
   }
diff --git a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
index 1c3747c..5c3984c 100644
--- a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
@@ -23,7 +23,7 @@
 import static com.google.gerrit.server.change.HashtagsUtil.cleanupHashtag;
 import static com.google.gerrit.server.git.MultiProgressMonitor.UNKNOWN;
 import static com.google.gerrit.server.git.receive.ReceiveConstants.COMMAND_REJECTION_MESSAGE_FOOTER;
-import static com.google.gerrit.server.git.receive.ReceiveConstants.ONLY_OWNER_CAN_MODIFY_WIP;
+import static com.google.gerrit.server.git.receive.ReceiveConstants.ONLY_CHANGE_OWNER_OR_PROJECT_OWNER_CAN_MODIFY_WIP;
 import static com.google.gerrit.server.git.receive.ReceiveConstants.PUSH_OPTION_SKIP_VALIDATION;
 import static com.google.gerrit.server.git.receive.ReceiveConstants.SAME_CHANGE_ID_IN_MULTIPLE_CHANGES;
 import static com.google.gerrit.server.git.validators.CommitValidators.NEW_PATCHSET_PATTERN;
@@ -2528,8 +2528,10 @@
       if (magicBranch != null
           && (magicBranch.workInProgress || magicBranch.ready)
           && magicBranch.workInProgress != change.isWorkInProgress()
-          && !user.getAccountId().equals(change.getOwner())) {
-        reject(inputCommand, ONLY_OWNER_CAN_MODIFY_WIP);
+          && (!user.getAccountId().equals(change.getOwner())
+              && !permissions.test(ProjectPermission.WRITE_CONFIG)
+              && !permissionBackend.user(user).test(GlobalPermission.ADMINISTRATE_SERVER))) {
+        reject(inputCommand, ONLY_CHANGE_OWNER_OR_PROJECT_OWNER_CAN_MODIFY_WIP);
         return false;
       }
 
@@ -2942,9 +2944,8 @@
 
                 for (Ref ref : byCommit.get(c.copy())) {
                   PatchSet.Id psId = PatchSet.Id.fromRef(ref.getName());
-                  Optional<ChangeData> cd =
-                      executeIndexQuery(() -> byLegacyId(psId.getParentKey()));
-                  if (cd.isPresent() && cd.get().change().getDest().equals(branch)) {
+                  Optional<ChangeNotes> notes = getChangeNotes(psId.getParentKey());
+                  if (notes.isPresent() && notes.get().getChange().getDest().equals(branch)) {
                     existingPatchSets++;
                     bu.addOp(
                         psId.getParentKey(),
@@ -3007,6 +3008,14 @@
     }
   }
 
+  private Optional<ChangeNotes> getChangeNotes(Change.Id changeId) throws OrmException {
+    try {
+      return Optional.of(notesFactory.createChecked(db, project.getNameKey(), changeId));
+    } catch (NoSuchChangeException e) {
+      return Optional.empty();
+    }
+  }
+
   private <T> T executeIndexQuery(Action<T> action) throws OrmException {
     try {
       return retryHelper.execute(ActionType.INDEX_QUERY, action, OrmException.class::isInstance);
@@ -3055,14 +3064,6 @@
     return r;
   }
 
-  private Optional<ChangeData> byLegacyId(Change.Id legacyId) throws OrmException {
-    List<ChangeData> res = queryProvider.get().byLegacyChangeId(legacyId);
-    if (res.isEmpty()) {
-      return Optional.empty();
-    }
-    return Optional.of(res.get(0));
-  }
-
   private Map<String, Ref> allRefs() {
     return allRefsWatcher.getAllRefs();
   }
diff --git a/java/com/google/gerrit/server/git/receive/ReceiveConstants.java b/java/com/google/gerrit/server/git/receive/ReceiveConstants.java
index 92723e0..b71f01e 100644
--- a/java/com/google/gerrit/server/git/receive/ReceiveConstants.java
+++ b/java/com/google/gerrit/server/git/receive/ReceiveConstants.java
@@ -20,8 +20,8 @@
   public static final String PUSH_OPTION_SKIP_VALIDATION = "skip-validation";
 
   @VisibleForTesting
-  public static final String ONLY_OWNER_CAN_MODIFY_WIP =
-      "only change owner can modify Work-in-Progress";
+  public static final String ONLY_CHANGE_OWNER_OR_PROJECT_OWNER_CAN_MODIFY_WIP =
+      "only change owner or project owner can modify Work-in-Progress";
 
   static final String COMMAND_REJECTION_MESSAGE_FOOTER =
       "Please read the documentation and contact an administrator\n"
diff --git a/java/com/google/gerrit/server/plugins/PluginsCollection.java b/java/com/google/gerrit/server/plugins/PluginsCollection.java
index 9dbc956..0d2a018 100644
--- a/java/com/google/gerrit/server/plugins/PluginsCollection.java
+++ b/java/com/google/gerrit/server/plugins/PluginsCollection.java
@@ -36,7 +36,7 @@
   private final Provider<InstallPlugin> install;
 
   @Inject
-  PluginsCollection(
+  public PluginsCollection(
       DynamicMap<RestView<PluginResource>> views,
       PluginLoader loader,
       Provider<ListPlugins> list,
diff --git a/java/com/google/gerrit/server/restapi/access/AccessCollection.java b/java/com/google/gerrit/server/restapi/access/AccessCollection.java
index d4528c5..8ae2ce7 100644
--- a/java/com/google/gerrit/server/restapi/access/AccessCollection.java
+++ b/java/com/google/gerrit/server/restapi/access/AccessCollection.java
@@ -30,7 +30,7 @@
   private final DynamicMap<RestView<AccessResource>> views;
 
   @Inject
-  AccessCollection(Provider<ListAccess> list, DynamicMap<RestView<AccessResource>> views) {
+  public AccessCollection(Provider<ListAccess> list, DynamicMap<RestView<AccessResource>> views) {
     this.list = list;
     this.views = views;
   }
diff --git a/java/com/google/gerrit/server/restapi/account/AccountsCollection.java b/java/com/google/gerrit/server/restapi/account/AccountsCollection.java
index e6fd037..6cec565 100644
--- a/java/com/google/gerrit/server/restapi/account/AccountsCollection.java
+++ b/java/com/google/gerrit/server/restapi/account/AccountsCollection.java
@@ -20,6 +20,7 @@
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
+import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.extensions.restapi.RestCollection;
 import com.google.gerrit.extensions.restapi.RestView;
 import com.google.gerrit.extensions.restapi.TopLevelResource;
@@ -50,7 +51,7 @@
   private final CreateAccount.Factory createAccountFactory;
 
   @Inject
-  AccountsCollection(
+  public AccountsCollection(
       Provider<CurrentUser> self,
       AccountResolver resolver,
       AccountControl.Factory accountControlFactory,
@@ -160,7 +161,7 @@
   }
 
   @Override
-  public CreateAccount create(TopLevelResource parent, IdString username) {
+  public CreateAccount create(TopLevelResource parent, IdString username) throws RestApiException {
     return createAccountFactory.create(username.get());
   }
 }
diff --git a/java/com/google/gerrit/server/restapi/change/ChangesCollection.java b/java/com/google/gerrit/server/restapi/change/ChangesCollection.java
index bf8bb1f..58ea185 100644
--- a/java/com/google/gerrit/server/restapi/change/ChangesCollection.java
+++ b/java/com/google/gerrit/server/restapi/change/ChangesCollection.java
@@ -56,7 +56,7 @@
   private final ProjectCache projectCache;
 
   @Inject
-  ChangesCollection(
+  public ChangesCollection(
       Provider<ReviewDb> db,
       Provider<CurrentUser> user,
       Provider<QueryChanges> queryFactory,
diff --git a/java/com/google/gerrit/server/restapi/change/Move.java b/java/com/google/gerrit/server/restapi/change/Move.java
index 5fcf967..8d144fa 100644
--- a/java/com/google/gerrit/server/restapi/change/Move.java
+++ b/java/com/google/gerrit/server/restapi/change/Move.java
@@ -21,6 +21,7 @@
 
 import com.google.common.base.Strings;
 import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.common.Nullable;
 import com.google.gerrit.common.TimeUtil;
 import com.google.gerrit.common.data.LabelType;
 import com.google.gerrit.extensions.api.changes.MoveInput;
@@ -145,12 +146,13 @@
     }
     projectCache.checkedGet(project).checkStatePermitsWrite();
 
+    Op op = new Op(input);
     try (BatchUpdate u =
         updateFactory.create(dbProvider.get(), project, caller, TimeUtil.nowTs())) {
-      u.addOp(change.getId(), new Op(input));
+      u.addOp(change.getId(), op);
       u.execute();
     }
-    return json.noOptions().format(project, rsrc.getId());
+    return json.noOptions().format(op.getChange());
   }
 
   private class Op implements BatchUpdateOp {
@@ -163,6 +165,11 @@
       this.input = input;
     }
 
+    @Nullable
+    public Change getChange() {
+      return change;
+    }
+
     @Override
     public boolean updateChange(ChangeContext ctx)
         throws OrmException, ResourceConflictException, IOException {
diff --git a/java/com/google/gerrit/server/restapi/change/PostReview.java b/java/com/google/gerrit/server/restapi/change/PostReview.java
index 489eaeb..e6f4f69 100644
--- a/java/com/google/gerrit/server/restapi/change/PostReview.java
+++ b/java/com/google/gerrit/server/restapi/change/PostReview.java
@@ -572,7 +572,7 @@
     Set<String> revisionFilePaths = getAffectedFilePaths(revision);
     for (Map.Entry<String, List<T>> entry : commentsPerPath.entrySet()) {
       String path = entry.getKey();
-      PatchSet.Id patchSetId = revision.getChange().currentPatchSetId();
+      PatchSet.Id patchSetId = revision.getPatchSet().getId();
       ensurePathRefersToAvailableOrMagicFile(path, revisionFilePaths, patchSetId);
 
       List<T> comments = entry.getValue();
diff --git a/java/com/google/gerrit/server/restapi/change/SetReadyForReview.java b/java/com/google/gerrit/server/restapi/change/SetReadyForReview.java
index 5298857..8fe5612 100644
--- a/java/com/google/gerrit/server/restapi/change/SetReadyForReview.java
+++ b/java/com/google/gerrit/server/restapi/change/SetReadyForReview.java
@@ -33,6 +33,7 @@
 import com.google.gerrit.server.permissions.GlobalPermission;
 import com.google.gerrit.server.permissions.PermissionBackend;
 import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.permissions.ProjectPermission;
 import com.google.gerrit.server.update.BatchUpdate;
 import com.google.gerrit.server.update.RetryHelper;
 import com.google.gerrit.server.update.RetryingRestModifyView;
@@ -66,7 +67,11 @@
       throws RestApiException, UpdateException, PermissionBackendException {
     Change change = rsrc.getChange();
     if (!rsrc.isUserOwner()
-        && !permissionBackend.currentUser().test(GlobalPermission.ADMINISTRATE_SERVER)) {
+        && !permissionBackend.currentUser().test(GlobalPermission.ADMINISTRATE_SERVER)
+        && !permissionBackend
+            .currentUser()
+            .project(rsrc.getProject())
+            .test(ProjectPermission.WRITE_CONFIG)) {
       throw new AuthException("not allowed to set ready for review");
     }
 
@@ -96,8 +101,13 @@
                 rsrc.getChange().getStatus() == Status.NEW && rsrc.getChange().isWorkInProgress(),
                 or(
                     rsrc.isUserOwner(),
-                    permissionBackend
-                        .currentUser()
-                        .testCond(GlobalPermission.ADMINISTRATE_SERVER))));
+                    or(
+                        permissionBackend
+                            .currentUser()
+                            .testCond(GlobalPermission.ADMINISTRATE_SERVER),
+                        permissionBackend
+                            .currentUser()
+                            .project(rsrc.getProject())
+                            .testCond(ProjectPermission.WRITE_CONFIG)))));
   }
 }
diff --git a/java/com/google/gerrit/server/restapi/change/SetWorkInProgress.java b/java/com/google/gerrit/server/restapi/change/SetWorkInProgress.java
index 93568d5..9524903 100644
--- a/java/com/google/gerrit/server/restapi/change/SetWorkInProgress.java
+++ b/java/com/google/gerrit/server/restapi/change/SetWorkInProgress.java
@@ -33,6 +33,7 @@
 import com.google.gerrit.server.permissions.GlobalPermission;
 import com.google.gerrit.server.permissions.PermissionBackend;
 import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.permissions.ProjectPermission;
 import com.google.gerrit.server.update.BatchUpdate;
 import com.google.gerrit.server.update.RetryHelper;
 import com.google.gerrit.server.update.RetryingRestModifyView;
@@ -67,7 +68,11 @@
     Change change = rsrc.getChange();
 
     if (!rsrc.isUserOwner()
-        && !permissionBackend.currentUser().test(GlobalPermission.ADMINISTRATE_SERVER)) {
+        && !permissionBackend.currentUser().test(GlobalPermission.ADMINISTRATE_SERVER)
+        && !permissionBackend
+            .currentUser()
+            .project(rsrc.getProject())
+            .test(ProjectPermission.WRITE_CONFIG)) {
       throw new AuthException("not allowed to set work in progress");
     }
 
@@ -97,8 +102,13 @@
                 rsrc.getChange().getStatus() == Status.NEW && !rsrc.getChange().isWorkInProgress(),
                 or(
                     rsrc.isUserOwner(),
-                    permissionBackend
-                        .currentUser()
-                        .testCond(GlobalPermission.ADMINISTRATE_SERVER))));
+                    or(
+                        permissionBackend
+                            .currentUser()
+                            .testCond(GlobalPermission.ADMINISTRATE_SERVER),
+                        permissionBackend
+                            .currentUser()
+                            .project(rsrc.getProject())
+                            .testCond(ProjectPermission.WRITE_CONFIG)))));
   }
 }
diff --git a/java/com/google/gerrit/server/restapi/config/ConfigCollection.java b/java/com/google/gerrit/server/restapi/config/ConfigCollection.java
index 934dbc1..47f4134 100644
--- a/java/com/google/gerrit/server/restapi/config/ConfigCollection.java
+++ b/java/com/google/gerrit/server/restapi/config/ConfigCollection.java
@@ -29,7 +29,7 @@
   private final DynamicMap<RestView<ConfigResource>> views;
 
   @Inject
-  ConfigCollection(DynamicMap<RestView<ConfigResource>> views) {
+  public ConfigCollection(DynamicMap<RestView<ConfigResource>> views) {
     this.views = views;
   }
 
diff --git a/java/com/google/gerrit/server/restapi/config/TopMenuCollection.java b/java/com/google/gerrit/server/restapi/config/TopMenuCollection.java
index 36a1b04..cca1475 100644
--- a/java/com/google/gerrit/server/restapi/config/TopMenuCollection.java
+++ b/java/com/google/gerrit/server/restapi/config/TopMenuCollection.java
@@ -25,7 +25,7 @@
 import com.google.inject.Singleton;
 
 @Singleton
-class TopMenuCollection implements ChildCollection<ConfigResource, TopMenuResource> {
+public class TopMenuCollection implements ChildCollection<ConfigResource, TopMenuResource> {
   private final DynamicMap<RestView<TopMenuResource>> views;
   private final ListTopMenus list;
 
diff --git a/java/com/google/gerrit/server/restapi/group/AddMembers.java b/java/com/google/gerrit/server/restapi/group/AddMembers.java
index 9ddafe3..461989d 100644
--- a/java/com/google/gerrit/server/restapi/group/AddMembers.java
+++ b/java/com/google/gerrit/server/restapi/group/AddMembers.java
@@ -211,12 +211,12 @@
     return result;
   }
 
-  static class PutMember implements RestModifyView<GroupResource, Input> {
+  public static class PutMember implements RestModifyView<GroupResource, Input> {
 
     private final AddMembers put;
     private final String id;
 
-    PutMember(AddMembers put, String id) {
+    public PutMember(AddMembers put, String id) {
       this.put = put;
       this.id = id;
     }
@@ -240,11 +240,11 @@
   }
 
   @Singleton
-  static class UpdateMember implements RestModifyView<MemberResource, Input> {
+  public static class UpdateMember implements RestModifyView<MemberResource, Input> {
     private final GetMember get;
 
     @Inject
-    UpdateMember(GetMember get) {
+    public UpdateMember(GetMember get) {
       this.get = get;
     }
 
diff --git a/java/com/google/gerrit/server/restapi/group/AddSubgroups.java b/java/com/google/gerrit/server/restapi/group/AddSubgroups.java
index e11f389..d0be5ac 100644
--- a/java/com/google/gerrit/server/restapi/group/AddSubgroups.java
+++ b/java/com/google/gerrit/server/restapi/group/AddSubgroups.java
@@ -127,12 +127,12 @@
     groupsUpdateProvider.get().updateGroup(parentGroupUuid, groupUpdate);
   }
 
-  static class PutSubgroup implements RestModifyView<GroupResource, Input> {
+  public static class PutSubgroup implements RestModifyView<GroupResource, Input> {
 
     private final AddSubgroups addSubgroups;
     private final String id;
 
-    PutSubgroup(AddSubgroups addSubgroups, String id) {
+    public PutSubgroup(AddSubgroups addSubgroups, String id) {
       this.addSubgroups = addSubgroups;
       this.id = id;
     }
@@ -156,11 +156,11 @@
   }
 
   @Singleton
-  static class UpdateSubgroup implements RestModifyView<SubgroupResource, Input> {
+  public static class UpdateSubgroup implements RestModifyView<SubgroupResource, Input> {
     private final Provider<GetSubgroup> get;
 
     @Inject
-    UpdateSubgroup(Provider<GetSubgroup> get) {
+    public UpdateSubgroup(Provider<GetSubgroup> get) {
       this.get = get;
     }
 
diff --git a/java/com/google/gerrit/server/restapi/group/DeleteMembers.java b/java/com/google/gerrit/server/restapi/group/DeleteMembers.java
index 3685469..bcacb65 100644
--- a/java/com/google/gerrit/server/restapi/group/DeleteMembers.java
+++ b/java/com/google/gerrit/server/restapi/group/DeleteMembers.java
@@ -92,12 +92,12 @@
   }
 
   @Singleton
-  static class DeleteMember implements RestModifyView<MemberResource, Input> {
+  public static class DeleteMember implements RestModifyView<MemberResource, Input> {
 
     private final Provider<DeleteMembers> delete;
 
     @Inject
-    DeleteMember(Provider<DeleteMembers> delete) {
+    public DeleteMember(Provider<DeleteMembers> delete) {
       this.delete = delete;
     }
 
diff --git a/java/com/google/gerrit/server/restapi/group/DeleteSubgroups.java b/java/com/google/gerrit/server/restapi/group/DeleteSubgroups.java
index 0eba8c7..934698b 100644
--- a/java/com/google/gerrit/server/restapi/group/DeleteSubgroups.java
+++ b/java/com/google/gerrit/server/restapi/group/DeleteSubgroups.java
@@ -96,12 +96,12 @@
   }
 
   @Singleton
-  static class DeleteSubgroup implements RestModifyView<SubgroupResource, Input> {
+  public static class DeleteSubgroup implements RestModifyView<SubgroupResource, Input> {
 
     private final Provider<DeleteSubgroups> delete;
 
     @Inject
-    DeleteSubgroup(Provider<DeleteSubgroups> delete) {
+    public DeleteSubgroup(Provider<DeleteSubgroups> delete) {
       this.delete = delete;
     }
 
diff --git a/java/com/google/gerrit/server/restapi/group/GroupsCollection.java b/java/com/google/gerrit/server/restapi/group/GroupsCollection.java
index 38b22a9..fba1f1f 100644
--- a/java/com/google/gerrit/server/restapi/group/GroupsCollection.java
+++ b/java/com/google/gerrit/server/restapi/group/GroupsCollection.java
@@ -24,6 +24,7 @@
 import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.NeedsParams;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
+import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.extensions.restapi.RestCollection;
 import com.google.gerrit.extensions.restapi.RestView;
 import com.google.gerrit.extensions.restapi.TopLevelResource;
@@ -58,7 +59,7 @@
   private boolean hasQuery2;
 
   @Inject
-  GroupsCollection(
+  public GroupsCollection(
       DynamicMap<RestView<GroupResource>> views,
       Provider<ListGroups> list,
       Provider<QueryGroups> queryGroups,
@@ -199,7 +200,7 @@
   }
 
   @Override
-  public CreateGroup create(TopLevelResource root, IdString name) {
+  public CreateGroup create(TopLevelResource root, IdString name) throws RestApiException {
     return createGroup.create(name.get());
   }
 
diff --git a/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java b/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java
index 3af8424..1ba993c 100644
--- a/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java
+++ b/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java
@@ -60,7 +60,7 @@
   private boolean hasQuery;
 
   @Inject
-  ProjectsCollection(
+  public ProjectsCollection(
       DynamicMap<RestView<ProjectResource>> views,
       Provider<ListProjects> list,
       Provider<QueryProjects> queryProjects,
@@ -181,7 +181,7 @@
   }
 
   @Override
-  public CreateProject create(TopLevelResource parent, IdString name) {
+  public CreateProject create(TopLevelResource parent, IdString name) throws RestApiException {
     return createProjectFactory.create(name.get());
   }
 }
diff --git a/java/com/google/gwtexpui/server/CacheHeaders.java b/java/com/google/gerrit/util/http/CacheHeaders.java
similarity index 98%
rename from java/com/google/gwtexpui/server/CacheHeaders.java
rename to java/com/google/gerrit/util/http/CacheHeaders.java
index 0e5e425..454587c 100644
--- a/java/com/google/gwtexpui/server/CacheHeaders.java
+++ b/java/com/google/gerrit/util/http/CacheHeaders.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gwtexpui.server;
+package com.google.gerrit.util.http;
 
 import static java.util.concurrent.TimeUnit.DAYS;
 import static java.util.concurrent.TimeUnit.SECONDS;
diff --git a/java/com/google/gwtexpui/linker/BUILD b/java/com/google/gwtexpui/linker/BUILD
deleted file mode 100644
index 5c5c600..0000000
--- a/java/com/google/gwtexpui/linker/BUILD
+++ /dev/null
@@ -1,6 +0,0 @@
-java_library(
-    name = "server",
-    srcs = glob(["server/*.java"]),
-    visibility = ["//visibility:public"],
-    deps = ["//lib:servlet-api-3_1"],
-)
diff --git a/java/com/google/gwtexpui/server/BUILD b/java/com/google/gwtexpui/server/BUILD
deleted file mode 100644
index 9b81564..0000000
--- a/java/com/google/gwtexpui/server/BUILD
+++ /dev/null
@@ -1,6 +0,0 @@
-java_library(
-    name = "server",
-    srcs = glob(["**/*.java"]),
-    visibility = ["//visibility:public"],
-    deps = ["//lib:servlet-api-3_1"],
-)
diff --git a/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java b/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java
index f17165e..1d0f3ac 100644
--- a/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java
@@ -728,6 +728,17 @@
   }
 
   @Test
+  public void deleteStarLabelsFromChangeWithoutStarLabels() throws Exception {
+    PushOneCommit.Result r = createChange();
+    String triplet = project.get() + "~master~" + r.getChangeId();
+    assertThat(gApi.accounts().self().getStars(triplet)).isEmpty();
+
+    gApi.accounts().self().setStars(triplet, new StarsInput());
+
+    assertThat(gApi.accounts().self().getStars(triplet)).isEmpty();
+  }
+
+  @Test
   public void starWithDefaultAndIgnoreLabel() throws Exception {
     PushOneCommit.Result r = createChange();
     String triplet = project.get() + "~master~" + r.getChangeId();
diff --git a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
index b85e2f2..3a3a6be 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -433,6 +433,19 @@
   }
 
   @Test
+  public void setWorkInProgressAllowedAsProjectOwner() throws Exception {
+    setApiUser(user);
+    String changeId =
+        gApi.changes().create(new ChangeInput(project.get(), "master", "Test Change")).get().id;
+
+    com.google.gerrit.acceptance.TestAccount user2 = accountCreator.user2();
+    grant(project, "refs/*", Permission.OWNER, false, REGISTERED_USERS);
+    setApiUser(user2);
+    gApi.changes().id(changeId).setWorkInProgress();
+    assertThat(gApi.changes().id(changeId).get().workInProgress).isTrue();
+  }
+
+  @Test
   public void setReadyForReviewNotAllowedWithoutPermission() throws Exception {
     PushOneCommit.Result rready = createChange();
     String changeId = rready.getChangeId();
@@ -457,6 +470,20 @@
   }
 
   @Test
+  public void setReadyForReviewAllowedAsProjectOwner() throws Exception {
+    setApiUser(user);
+    String changeId =
+        gApi.changes().create(new ChangeInput(project.get(), "master", "Test Change")).get().id;
+    gApi.changes().id(changeId).setWorkInProgress();
+
+    com.google.gerrit.acceptance.TestAccount user2 = accountCreator.user2();
+    grant(project, "refs/*", Permission.OWNER, false, REGISTERED_USERS);
+    setApiUser(user2);
+    gApi.changes().id(changeId).setReadyForReview();
+    assertThat(gApi.changes().id(changeId).get().workInProgress).isNull();
+  }
+
+  @Test
   public void hasReviewStarted() throws Exception {
     PushOneCommit.Result r = createWorkInProgressChange();
     String changeId = r.getChangeId();
diff --git a/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java b/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java
index 1ae3283..8a3d0f3 100644
--- a/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java
@@ -1226,6 +1226,26 @@
   }
 
   @Test
+  public void commentOnNonExistingFile() throws Exception {
+    PushOneCommit.Result r = createChange();
+    r = updateChange(r, "new content");
+    CommentInput in = new CommentInput();
+    in.line = 1;
+    in.message = "nit: trailing whitespace";
+    in.path = "non-existing.txt";
+    ReviewInput reviewInput = new ReviewInput();
+    Map<String, List<CommentInput>> comments = new HashMap<>();
+    comments.put("non-existing.txt", Collections.singletonList(in));
+    reviewInput.comments = comments;
+    reviewInput.message = "comment test";
+
+    exception.expect(BadRequestException.class);
+    exception.expectMessage(
+        String.format("not found in revision %d,1", r.getChange().change().getId().id));
+    gApi.changes().id(r.getChangeId()).revision(1).review(reviewInput);
+  }
+
+  @Test
   public void patch() throws Exception {
     PushOneCommit.Result r = createChange();
     ChangeApi changeApi = gApi.changes().id(r.getChangeId());
diff --git a/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java b/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
index 1d7f3d9..cfa7ec4 100644
--- a/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
+++ b/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
@@ -276,7 +276,7 @@
 
   @Test
   public void output() throws Exception {
-    String url = canonicalWebUrl.get() + "#/c/" + project.get() + "/+/";
+    String url = canonicalWebUrl.get() + "c/" + project.get() + "/+/";
     ObjectId initialHead = testRepo.getRepository().resolve("HEAD");
     PushOneCommit.Result r1 = pushTo("refs/for/master");
     Change.Id id1 = r1.getChange().getId();
@@ -328,7 +328,7 @@
     assertPushOk(pushHead(testRepo, master, false), master);
 
     // Attempt to push amended commit to same change
-    String url = canonicalWebUrl.get() + "#/c/" + project.get() + "/+/" + r.getChange().getId();
+    String url = canonicalWebUrl.get() + "c/" + project.get() + "/+/" + r.getChange().getId();
     r = amendChange(r.getChangeId(), "refs/for/master");
     r.assertErrorStatus("change " + url + " closed");
 
@@ -354,7 +354,7 @@
     assertPushOk(pushHead(testRepo, master, false), master);
 
     // Attempt to push amended commit to same change
-    String url = canonicalWebUrl.get() + "#/c/" + project.get() + "/+/" + r.getChange().getId();
+    String url = canonicalWebUrl.get() + "c/" + project.get() + "/+/" + r.getChange().getId();
     r = amendChange(r.getChangeId(), "refs/for/master");
     r.assertErrorStatus("change " + url + " closed");
 
@@ -656,11 +656,11 @@
     assertThat(r.getChange().change().getOwner()).isEqualTo(user.id);
     assertThat(r.getChange().change().isWorkInProgress()).isTrue();
 
-    // Other user trying to move from WIP to ready should fail.
+    // Admin user trying to move from WIP to ready should succeed.
     GitUtil.fetch(testRepo, r.getPatchSet().getRefName() + ":ps");
     testRepo.reset("ps");
-    r = amendChange(r.getChangeId(), "refs/for/master%ready", admin, testRepo);
-    r.assertErrorStatus(ReceiveConstants.ONLY_OWNER_CAN_MODIFY_WIP);
+    r = amendChange(r.getChangeId(), "refs/for/master%ready", user, testRepo);
+    r.assertOkStatus();
 
     // Other user trying to move from WIP to WIP should succeed.
     r = amendChange(r.getChangeId(), "refs/for/master%wip", admin, testRepo);
@@ -672,14 +672,29 @@
     r.assertOkStatus();
     assertThat(r.getChange().change().isWorkInProgress()).isFalse();
 
-    // Other user trying to move from ready to WIP should fail.
+    // Admin user trying to move from ready to WIP should succeed.
     GitUtil.fetch(testRepo, r.getPatchSet().getRefName() + ":ps");
     testRepo.reset("ps");
     r = amendChange(r.getChangeId(), "refs/for/master%wip", admin, testRepo);
-    r.assertErrorStatus(ReceiveConstants.ONLY_OWNER_CAN_MODIFY_WIP);
+    r.assertOkStatus();
 
-    // Other user trying to move from ready to ready should succeed.
-    r = amendChange(r.getChangeId(), "refs/for/master%ready", admin, testRepo);
+    // Other user trying to move from wip to wip should succeed.
+    r = amendChange(r.getChangeId(), "refs/for/master%wip", admin, testRepo);
+    r.assertOkStatus();
+
+    // Non owner, non admin and non project owner cannot flip wip bit:
+    TestAccount user2 = accountCreator.user2();
+    grant(
+        project, "refs/*", Permission.FORGE_COMMITTER, false, SystemGroupBackend.REGISTERED_USERS);
+    TestRepository<?> user2Repo = cloneProject(project, user2);
+    GitUtil.fetch(user2Repo, r.getPatchSet().getRefName() + ":ps");
+    user2Repo.reset("ps");
+    r = amendChange(r.getChangeId(), "refs/for/master%ready", user2, user2Repo);
+    r.assertErrorStatus(ReceiveConstants.ONLY_CHANGE_OWNER_OR_PROJECT_OWNER_CAN_MODIFY_WIP);
+
+    // Project owner trying to move from WIP to ready should succeed.
+    allow("refs/*", Permission.OWNER, SystemGroupBackend.REGISTERED_USERS);
+    r = amendChange(r.getChangeId(), "refs/for/master%ready", user2, user2Repo);
     r.assertOkStatus();
   }
 
@@ -700,7 +715,7 @@
     r.assertMessage(
         "Updated Changes:\n  "
             + canonicalWebUrl.get()
-            + "#/c/"
+            + "c/"
             + project.get()
             + "/+/"
             + r.getChange().getId()
diff --git a/javatests/com/google/gerrit/acceptance/rest/account/WatchedProjectsIT.java b/javatests/com/google/gerrit/acceptance/rest/account/WatchedProjectsIT.java
index 9edafb8..bc84593 100644
--- a/javatests/com/google/gerrit/acceptance/rest/account/WatchedProjectsIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/account/WatchedProjectsIT.java
@@ -235,4 +235,9 @@
     assertThat(persistedWatchedProjects).doesNotContain(pwi);
     assertThat(persistedWatchedProjects).containsAllIn(projectsToWatch);
   }
+
+  @Test
+  public void postWithoutBody() throws Exception {
+    adminRestSession.post("/accounts/" + admin.username + "/watched.projects").assertOK();
+  }
 }
diff --git a/javatests/com/google/gerrit/acceptance/server/rules/BUILD b/javatests/com/google/gerrit/acceptance/server/rules/BUILD
index 2e96c0b..1f547f7 100644
--- a/javatests/com/google/gerrit/acceptance/server/rules/BUILD
+++ b/javatests/com/google/gerrit/acceptance/server/rules/BUILD
@@ -5,6 +5,6 @@
     group = "server_rules",
     labels = ["server"],
     deps = [
-        "@prolog_runtime//jar",
+        "@prolog-runtime//jar",
     ],
 )
diff --git a/javatests/com/google/gerrit/acceptance/ssh/AbstractIndexTests.java b/javatests/com/google/gerrit/acceptance/ssh/AbstractIndexTests.java
new file mode 100644
index 0000000..c72edfb
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/ssh/AbstractIndexTests.java
@@ -0,0 +1,67 @@
+// Copyright (C) 2018 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.acceptance.ssh;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.FluentIterable;
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.NoHttpd;
+import com.google.gerrit.acceptance.PushOneCommit;
+import com.google.gerrit.acceptance.UseSsh;
+import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.server.query.change.ChangeData;
+import com.google.inject.Injector;
+import java.util.List;
+import org.junit.Test;
+
+@NoHttpd
+@UseSsh
+public abstract class AbstractIndexTests extends AbstractDaemonTest {
+  /** @param injector injector */
+  public abstract void configureIndex(Injector injector) throws Exception;
+
+  @Test
+  public void indexChange() throws Exception {
+    configureIndex(server.getTestInjector());
+
+    PushOneCommit.Result change = createChange("first change", "test1.txt", "test1");
+    String changeId = change.getChangeId();
+    String changeLegacyId = change.getChange().getId().toString();
+
+    disableChangeIndexWrites();
+    amendChange(changeId, "second test", "test2.txt", "test2");
+
+    assertQuery("message:second", change.getChange(), false);
+    enableChangeIndexWrites();
+
+    String cmd = Joiner.on(" ").join("gerrit", "index", "changes", changeLegacyId);
+    adminSshSession.exec(cmd);
+
+    assertQuery("message:second", change.getChange(), true);
+  }
+
+  protected void assertQuery(String q, ChangeData change, Boolean assertTrue) throws Exception {
+    List<ChangeInfo> result = query(q);
+    Iterable<Integer> ids = ids(result);
+    if (assertTrue) assertThat(ids).contains(change.getId().get());
+    else assertThat(ids).doesNotContain(change.getId().get());
+  }
+
+  protected static Iterable<Integer> ids(Iterable<ChangeInfo> changes) {
+    return FluentIterable.from(changes).transform(in -> in._number);
+  }
+}
diff --git a/javatests/com/google/gerrit/acceptance/ssh/BUILD b/javatests/com/google/gerrit/acceptance/ssh/BUILD
index 87b2920..eefd9d3 100644
--- a/javatests/com/google/gerrit/acceptance/ssh/BUILD
+++ b/javatests/com/google/gerrit/acceptance/ssh/BUILD
@@ -1,9 +1,38 @@
 load("//javatests/com/google/gerrit/acceptance:tests.bzl", "acceptance_tests")
 
+java_library(
+    name = "util",
+    testonly = 1,
+    srcs = ["AbstractIndexTests.java"],
+    deps = ["//java/com/google/gerrit/acceptance:lib"],
+)
+
 acceptance_tests(
-    srcs = glob(["*IT.java"]),
+    srcs = glob(
+        ["*IT.java"],
+        exclude = ["ElasticIndexIT.java"],
+    ),
     group = "ssh",
     labels = ["ssh"],
     vm_args = ["-Xmx512m"],
-    deps = ["//lib/commons:compress"],
+    deps = [
+        ":util",
+        "//lib/commons:compress",
+    ],
+)
+
+acceptance_tests(
+    srcs = ["ElasticIndexIT.java"],
+    group = "elastic",
+    labels = [
+        "elastic",
+        "docker",
+        "ssh",
+    ],
+    deps = [
+        ":util",
+        "//java/com/google/gerrit/elasticsearch",
+        "//javatests/com/google/gerrit/elasticsearch:elasticsearch_test_utils",
+        "//lib/commons:compress",
+    ],
 )
diff --git a/javatests/com/google/gerrit/acceptance/ssh/ElasticIndexIT.java b/javatests/com/google/gerrit/acceptance/ssh/ElasticIndexIT.java
new file mode 100644
index 0000000..bd0d67f
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/ssh/ElasticIndexIT.java
@@ -0,0 +1,62 @@
+// Copyright (C) 2018 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.acceptance.ssh;
+
+import com.google.gerrit.elasticsearch.ElasticContainer;
+import com.google.gerrit.elasticsearch.ElasticTestUtils;
+import com.google.gerrit.elasticsearch.ElasticTestUtils.ElasticNodeInfo;
+import com.google.gerrit.elasticsearch.ElasticVersion;
+import com.google.gerrit.testing.ConfigSuite;
+import com.google.inject.Injector;
+import java.util.UUID;
+import org.eclipse.jgit.lib.Config;
+
+public class ElasticIndexIT extends AbstractIndexTests {
+  private static ElasticContainer<?> container;
+
+  private static Config getConfig(ElasticVersion version) {
+    ElasticNodeInfo elasticNodeInfo;
+    try {
+      container = ElasticContainer.createAndStart(version);
+      elasticNodeInfo = new ElasticNodeInfo(container.getHttpHost().getPort());
+    } catch (Throwable t) {
+      return null;
+    }
+    String indicesPrefix = UUID.randomUUID().toString();
+    Config cfg = new Config();
+    ElasticTestUtils.configure(cfg, elasticNodeInfo.port, indicesPrefix);
+    return cfg;
+  }
+
+  @ConfigSuite.Default
+  public static Config elasticsearchV2() {
+    return getConfig(ElasticVersion.V2_4);
+  }
+
+  @ConfigSuite.Config
+  public static Config elasticsearchV5() {
+    return getConfig(ElasticVersion.V5_6);
+  }
+
+  @ConfigSuite.Config
+  public static Config elasticsearchV6() {
+    return getConfig(ElasticVersion.V6_2);
+  }
+
+  @Override
+  public void configureIndex(Injector injector) throws Exception {
+    ElasticTestUtils.createAllIndexes(injector);
+  }
+}
diff --git a/javatests/com/google/gerrit/acceptance/ssh/IndexIT.java b/javatests/com/google/gerrit/acceptance/ssh/IndexIT.java
new file mode 100644
index 0000000..196a1e5
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/ssh/IndexIT.java
@@ -0,0 +1,23 @@
+// Copyright (C) 2018 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.acceptance.ssh;
+
+import com.google.inject.Injector;
+
+public class IndexIT extends AbstractIndexTests {
+
+  @Override
+  public void configureIndex(Injector injector) throws Exception {}
+}
diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticContainer.java b/javatests/com/google/gerrit/elasticsearch/ElasticContainer.java
index c78f7c0..df15d8f 100644
--- a/javatests/com/google/gerrit/elasticsearch/ElasticContainer.java
+++ b/javatests/com/google/gerrit/elasticsearch/ElasticContainer.java
@@ -65,7 +65,7 @@
   }
 
   @Override
-  protected Set<Integer> getLivenessCheckPorts() {
+  public Set<Integer> getLivenessCheckPortNumbers() {
     return ImmutableSet.of(getMappedPort(ELASTICSEARCH_DEFAULT_PORT));
   }
 
diff --git a/javatests/com/google/gerrit/index/BUILD b/javatests/com/google/gerrit/index/BUILD
index d905188..14a7048 100644
--- a/javatests/com/google/gerrit/index/BUILD
+++ b/javatests/com/google/gerrit/index/BUILD
@@ -11,7 +11,7 @@
         "//java/com/google/gerrit/index:query_parser",
         "//lib:guava",
         "//lib:junit",
-        "//lib/antlr:java_runtime",
+        "//lib/antlr:java-runtime",
         "//lib/jgit/org.eclipse.jgit:jgit",
         "//lib/truth",
     ],
diff --git a/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java b/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
index f6d2568..bc3c9a9 100644
--- a/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
+++ b/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
@@ -71,6 +71,7 @@
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.meta.MetaDataUpdate;
 import com.google.gerrit.server.index.account.AccountField;
+import com.google.gerrit.server.index.account.AccountIndex;
 import com.google.gerrit.server.index.account.AccountIndexCollection;
 import com.google.gerrit.server.index.account.AccountIndexer;
 import com.google.gerrit.server.schema.SchemaCreator;
@@ -449,6 +450,18 @@
   }
 
   @Test
+  public void byDeletedAccount() throws Exception {
+    AccountInfo user = newAccountWithFullName("jdoe", "John Doe");
+    Account.Id userId = Account.Id.tryParse(user._accountId.toString()).get();
+    assertQuery("John", user);
+
+    for (AccountIndex index : indexes.getWriteIndexes()) {
+      index.delete(userId);
+    }
+    assertQuery("John");
+  }
+
+  @Test
   public void withLimit() throws Exception {
     String domain = name("test.com");
     AccountInfo user1 = newAccountWithEmail("user1", "user1@" + domain);
diff --git a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
index 95f2df3..cf85aeb 100644
--- a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
+++ b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
@@ -887,6 +887,18 @@
   }
 
   @Test
+  public void byMessageMixedCase() throws Exception {
+    TestRepository<Repo> repo = createProject("repo");
+    RevCommit commit1 = repo.parseBody(repo.commit().message("Hello gerrit").create());
+    Change change1 = insert(repo, newChangeForCommit(repo, commit1));
+    RevCommit commit2 = repo.parseBody(repo.commit().message("Hello Gerrit").create());
+    Change change2 = insert(repo, newChangeForCommit(repo, commit2));
+
+    assertQuery("message:gerrit", change2, change1);
+    assertQuery("message:Gerrit", change2, change1);
+  }
+
+  @Test
   public void byLabel() throws Exception {
     accountManager.authenticate(AuthRequest.forUser("anotheruser"));
     TestRepository<Repo> repo = createProject("repo");
diff --git a/javatests/com/google/gerrit/server/query/group/AbstractQueryGroupsTest.java b/javatests/com/google/gerrit/server/query/group/AbstractQueryGroupsTest.java
index bacbb60..750813a 100644
--- a/javatests/com/google/gerrit/server/query/group/AbstractQueryGroupsTest.java
+++ b/javatests/com/google/gerrit/server/query/group/AbstractQueryGroupsTest.java
@@ -50,6 +50,7 @@
 import com.google.gerrit.server.group.db.GroupsUpdate;
 import com.google.gerrit.server.group.db.InternalGroupUpdate;
 import com.google.gerrit.server.index.group.GroupField;
+import com.google.gerrit.server.index.group.GroupIndex;
 import com.google.gerrit.server.index.group.GroupIndexCollection;
 import com.google.gerrit.server.schema.SchemaCreator;
 import com.google.gerrit.server.util.ManualRequestContext;
@@ -104,6 +105,8 @@
 
   @Inject protected GroupIndexCollection indexes;
 
+  @Inject private GroupIndexCollection groupIndexes;
+
   protected LifecycleManager lifecycle;
   protected Injector injector;
   protected ReviewDb db;
@@ -392,6 +395,19 @@
     assertThat(rawFields.get().getValue(GroupField.UUID)).isEqualTo(uuid.get());
   }
 
+  @Test
+  public void byDeletedGroup() throws Exception {
+    GroupInfo group = createGroup(name("group"));
+    AccountGroup.UUID uuid = new AccountGroup.UUID(group.id);
+    String query = "uuid:" + uuid;
+    assertQuery(query, group);
+
+    for (GroupIndex index : groupIndexes.getWriteIndexes()) {
+      index.delete(uuid);
+    }
+    assertQuery(query);
+  }
+
   private Account.Id createAccountOutsideRequestContext(
       String username, String fullName, String email, boolean active) throws Exception {
     try (ManualRequestContext ctx = oneOffRequestContext.open()) {
diff --git a/lib/BUILD b/lib/BUILD
index c698afb..e2dbbf1 100644
--- a/lib/BUILD
+++ b/lib/BUILD
@@ -16,14 +16,14 @@
     data = ["//lib:LICENSE-Apache2.0"],
     neverlink = 1,
     visibility = ["//visibility:public"],
-    exports = ["@servlet_api_3_1//jar"],
+    exports = ["@servlet-api-3_1//jar"],
 )
 
 java_library(
     name = "servlet-api-3_1-without-neverlink",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@servlet_api_3_1//jar"],
+    exports = ["@servlet-api-3_1//jar"],
 )
 
 java_library(
@@ -48,17 +48,17 @@
 )
 
 java_library(
-    name = "gwtorm_client",
+    name = "gwtorm-client",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@gwtorm_client//jar"],
+    exports = ["@gwtorm-client//jar"],
 )
 
 java_library(
-    name = "gwtorm_client_src",
+    name = "gwtorm-client_src",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@gwtorm_client//jar:src"],
+    exports = ["@gwtorm-client//jar:src"],
 )
 
 java_library(
@@ -71,7 +71,7 @@
 java_library(
     name = "gwtorm",
     visibility = ["//visibility:public"],
-    exports = [":gwtorm_client"],
+    exports = [":gwtorm-client"],
     runtime_deps = [":protobuf"],
 )
 
@@ -151,21 +151,21 @@
     name = "tukaani-xz",
     data = ["//lib:LICENSE-xz"],
     visibility = ["//visibility:public"],
-    exports = ["@tukaani_xz//jar"],
+    exports = ["@tukaani-xz//jar"],
 )
 
 java_library(
     name = "mime-util",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@mime_util//jar"],
+    exports = ["@mime-util//jar"],
 )
 
 java_library(
     name = "guava-retrying",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@guava_retrying//jar"],
+    exports = ["@guava-retrying//jar"],
     runtime_deps = [":jsr305"],
 )
 
@@ -180,7 +180,7 @@
     name = "blame-cache",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@blame_cache//jar"],
+    exports = ["@blame-cache//jar"],
 )
 
 java_library(
@@ -213,7 +213,7 @@
     name = "hamcrest-core",
     data = ["//lib:LICENSE-DO_NOT_DISTRIBUTE"],
     visibility = ["//visibility:public"],
-    exports = ["@hamcrest_core//jar"],
+    exports = ["@hamcrest-core//jar"],
 )
 
 java_library(
@@ -245,7 +245,7 @@
         ":protobuf",
         "//lib/guice",
         "//lib/guice:guice-assistedinject",
-        "//lib/guice:javax-inject",
+        "//lib/guice:javax_inject",
         "//lib/ow2:ow2-asm",
         "//lib/ow2:ow2-asm-analysis",
         "//lib/ow2:ow2-asm-commons",
@@ -257,7 +257,7 @@
     name = "html-types",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@html_types//jar"],
+    exports = ["@html-types//jar"],
 )
 
 java_library(
diff --git a/lib/antlr/BUILD b/lib/antlr/BUILD
index 08c320b..c35c2b5 100644
--- a/lib/antlr/BUILD
+++ b/lib/antlr/BUILD
@@ -10,10 +10,10 @@
 ]]
 
 java_library(
-    name = "java_runtime",
+    name = "java-runtime",
     data = ["//lib:LICENSE-antlr"],
     visibility = ["//visibility:public"],
-    exports = ["@java_runtime//jar"],
+    exports = ["@java-runtime//jar"],
 )
 
 # See https://github.com/bazelbuild/bazel/issues/3542
@@ -29,10 +29,10 @@
 java_library(
     name = "tool",
     data = ["//lib:LICENSE-antlr"],
-    exports = ["@org_antlr//jar"],
+    exports = ["@org-antlr//jar"],
     runtime_deps = [
         ":antlr27",
-        ":java_runtime",
+        ":java-runtime",
         ":stringtemplate",
     ],
 )
diff --git a/lib/auto/BUILD b/lib/auto/BUILD
index 89adbde..1e722bc 100644
--- a/lib/auto/BUILD
+++ b/lib/auto/BUILD
@@ -2,8 +2,8 @@
     name = "auto-annotation-plugin",
     processor_class = "com.google.auto.value.processor.AutoAnnotationProcessor",
     deps = [
-        "@auto_value//jar",
-        "@auto_value_annotations//jar",
+        "@auto-value-annotations//jar",
+        "@auto-value//jar",
     ],
 )
 
@@ -11,8 +11,8 @@
     name = "auto-value-plugin",
     processor_class = "com.google.auto.value.processor.AutoValueProcessor",
     deps = [
-        "@auto_value//jar",
-        "@auto_value_annotations//jar",
+        "@auto-value-annotations//jar",
+        "@auto-value//jar",
     ],
 )
 
@@ -24,7 +24,7 @@
         ":auto-value-plugin",
     ],
     visibility = ["//visibility:public"],
-    exports = ["@auto_value//jar"],
+    exports = ["@auto-value//jar"],
 )
 
 java_library(
@@ -35,5 +35,5 @@
         ":auto-value-plugin",
     ],
     visibility = ["//visibility:public"],
-    exports = ["@auto_value_annotations//jar"],
+    exports = ["@auto-value-annotations//jar"],
 )
diff --git a/lib/codemirror/BUILD b/lib/codemirror/BUILD
index 9c03887..d0c9278 100644
--- a/lib/codemirror/BUILD
+++ b/lib/codemirror/BUILD
@@ -5,7 +5,7 @@
 java_library(
     name = "diff-match-patch",
     data = ["//lib:LICENSE-Apache2.0"],
-    runtime_deps = ["@diff_match_patch//jar"],
+    runtime_deps = ["@diff-match-patch//jar"],
 )
 
 pkg_cm()
diff --git a/lib/codemirror/cm.bzl b/lib/codemirror/cm.bzl
index 54d60d5..5088a05 100644
--- a/lib/codemirror/cm.bzl
+++ b/lib/codemirror/cm.bzl
@@ -55,11 +55,14 @@
     "eclipse",
     "elegant",
     "erlang-dark",
+    "gruvbox-dark",
     "hopscotch",
     "icecoder",
+    "idea",
     "isotope",
     "lesser-dark",
     "liquibyte",
+    "lucario",
     "material",
     "mbo",
     "mdn-like",
@@ -75,6 +78,7 @@
     "rubyblue",
     "seti",
     "solarized",
+    "ssms",
     "the-matrix",
     "tomorrow-night-bright",
     "tomorrow-night-eighties",
@@ -214,7 +218,7 @@
     "z80",
 ]
 
-CM_VERSION = "5.25.0"
+CM_VERSION = "5.37.0"
 
 TOP = "META-INF/resources/webjars/codemirror/%s" % CM_VERSION
 
@@ -231,8 +235,8 @@
 
 def pkg_cm():
   for archive, suffix, top, license in [
-      ('@codemirror_original//jar', '', TOP, LICENSE),
-      ('@codemirror_minified//jar', '_r', TOP_MINIFIED, LICENSE_MINIFIED)
+      ('@codemirror-original-gwt//jar', '', TOP, LICENSE),
+      ('@codemirror-minified-gwt//jar', '_r', TOP_MINIFIED, LICENSE_MINIFIED)
   ]:
     # Main JavaScript and addons
     genrule2(
@@ -306,13 +310,13 @@
           "echo '/** @license' >>$@",
           "echo 'LICENSE-Apache2.0' >>$@",
           "echo '*/' >>$@",
-          'unzip -p $(location @diff_match_patch//jar) %s/diff_match_patch.js >>$@' % DIFF_MATCH_PATCH_TOP,
+          'unzip -p $(location @diff-match-patch//jar) %s/diff_match_patch.js >>$@' % DIFF_MATCH_PATCH_TOP,
           "echo ';' >> $@",
           'unzip -p $(location %s) %s/addon/merge/merge.js >>$@' % (archive, top)
         ]
       ),
       tools = [
-        '@diff_match_patch//jar',
+        '@diff-match-patch//jar',
         # dependency just for license tracking.
         ':diff-match-patch',
         archive,
diff --git a/lib/commons/BUILD b/lib/commons/BUILD
index cb81a1d..bb36389 100644
--- a/lib/commons/BUILD
+++ b/lib/commons/BUILD
@@ -4,41 +4,41 @@
     name = "codec",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@commons_codec//jar"],
+    exports = ["@commons-codec//jar"],
 )
 
 java_library(
     name = "compress",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@commons_compress//jar"],
+    exports = ["@commons-compress//jar"],
 )
 
 java_library(
     name = "lang",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@commons_lang//jar"],
+    exports = ["@commons-lang//jar"],
 )
 
 java_library(
     name = "lang3",
     data = ["//lib:LICENSE-Apache2.0"],
-    exports = ["@commons_lang3//jar"],
+    exports = ["@commons-lang3//jar"],
 )
 
 java_library(
     name = "net",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@commons_net//jar"],
+    exports = ["@commons-net//jar"],
 )
 
 java_library(
     name = "dbcp",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@commons_dbcp//jar"],
+    exports = ["@commons-dbcp//jar"],
     runtime_deps = [":pool"],
 )
 
@@ -46,19 +46,19 @@
     name = "pool",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@commons_pool//jar"],
+    exports = ["@commons-pool//jar"],
 )
 
 java_library(
     name = "validator",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@commons_validator//jar"],
+    exports = ["@commons-validator//jar"],
 )
 
 java_library(
     name = "io",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@commons_io//jar"],
+    exports = ["@commons-io//jar"],
 )
diff --git a/lib/dropwizard/BUILD b/lib/dropwizard/BUILD
index dd14699..4ae12f1 100644
--- a/lib/dropwizard/BUILD
+++ b/lib/dropwizard/BUILD
@@ -2,5 +2,5 @@
     name = "dropwizard-core",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@dropwizard_core//jar"],
+    exports = ["@dropwizard-core//jar"],
 )
diff --git a/lib/easymock/BUILD b/lib/easymock/BUILD
index b579ec5..352d2a7 100644
--- a/lib/easymock/BUILD
+++ b/lib/easymock/BUILD
@@ -13,7 +13,7 @@
     name = "cglib-3_2",
     data = ["//lib:LICENSE-DO_NOT_DISTRIBUTE"],
     visibility = ["//visibility:public"],
-    exports = ["@cglib_3_2//jar"],
+    exports = ["@cglib-3_2//jar"],
 )
 
 java_library(
diff --git a/lib/guice/BUILD b/lib/guice/BUILD
index 9a9bf94..7f384e2 100644
--- a/lib/guice/BUILD
+++ b/lib/guice/BUILD
@@ -3,16 +3,16 @@
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
     exports = [
-        ":guice_library",
-        ":javax-inject",
+        ":guice-library",
+        ":javax_inject",
     ],
 )
 
 java_library(
-    name = "guice_library",
+    name = "guice-library",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@guice_library//jar"],
+    exports = ["@guice-library//jar"],
     runtime_deps = ["aopalliance"],
 )
 
@@ -20,7 +20,7 @@
     name = "guice-assistedinject",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@guice_assistedinject//jar"],
+    exports = ["@guice-assistedinject//jar"],
     runtime_deps = [":guice"],
 )
 
@@ -28,7 +28,7 @@
     name = "guice-servlet",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@guice_servlet//jar"],
+    exports = ["@guice-servlet//jar"],
     runtime_deps = [":guice"],
 )
 
@@ -39,7 +39,7 @@
 )
 
 java_library(
-    name = "javax-inject",
+    name = "javax_inject",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
     exports = ["@javax_inject//jar"],
diff --git a/lib/gwt/BUILD b/lib/gwt/BUILD
index 487e05b..fa2fef3 100644
--- a/lib/gwt/BUILD
+++ b/lib/gwt/BUILD
@@ -2,7 +2,7 @@
     name = n,
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@%s//jar" % n.replace("-", "_")],
+    exports = ["@%s//jar" % n],
 ) for n in [
     "ant",
     "colt",
@@ -34,12 +34,12 @@
     name = "javax-validation_src",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@javax_validation//jar:src"],
+    exports = ["@javax-validation//jar:src"],
 )
 
 java_library(
     name = "jsinterop-annotations_src",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@jsinterop_annotations//jar:src"],
+    exports = ["@jsinterop-annotations//jar:src"],
 )
diff --git a/lib/httpcomponents/BUILD b/lib/httpcomponents/BUILD
index 6e8fcd8..8e9fbc5 100644
--- a/lib/httpcomponents/BUILD
+++ b/lib/httpcomponents/BUILD
@@ -4,7 +4,7 @@
     name = "fluent-hc",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@fluent_hc//jar"],
+    exports = ["@fluent-hc//jar"],
     runtime_deps = [":httpclient"],
 )
 
@@ -43,5 +43,5 @@
 java_library(
     name = "httpcore-nio",
     data = ["//lib:LICENSE-Apache2.0"],
-    exports = ["@httpcore_nio//jar"],
+    exports = ["@httpcore-nio//jar"],
 )
diff --git a/lib/jackson/BUILD b/lib/jackson/BUILD
index c01890d..5c15193 100644
--- a/lib/jackson/BUILD
+++ b/lib/jackson/BUILD
@@ -5,5 +5,5 @@
 java_library(
     name = "jackson-core",
     data = ["//lib:LICENSE-Apache2.0"],
-    exports = ["@jackson_core//jar"],
+    exports = ["@jackson-core//jar"],
 )
diff --git a/lib/jetty/BUILD b/lib/jetty/BUILD
index c6ba9c8..c5f1da8 100644
--- a/lib/jetty/BUILD
+++ b/lib/jetty/BUILD
@@ -2,7 +2,7 @@
     name = "servlet",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@jetty_servlet//jar"],
+    exports = ["@jetty-servlet//jar"],
     runtime_deps = [":security"],
 )
 
@@ -10,7 +10,7 @@
     name = "security",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@jetty_security//jar"],
+    exports = ["@jetty-security//jar"],
     runtime_deps = [":server"],
 )
 
@@ -18,7 +18,7 @@
     name = "servlets",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@jetty_servlets//jar"],
+    exports = ["@jetty-servlets//jar"],
 )
 
 java_library(
@@ -28,7 +28,7 @@
     exports = [
         ":continuation",
         ":http",
-        "@jetty_server//jar",
+        "@jetty-server//jar",
     ],
 )
 
@@ -39,7 +39,7 @@
     exports = [
         ":continuation",
         ":http",
-        "@jetty_jmx//jar",
+        "@jetty-jmx//jar",
     ],
 )
 
@@ -47,7 +47,7 @@
     name = "continuation",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@jetty_continuation//jar"],
+    exports = ["@jetty-continuation//jar"],
 )
 
 java_library(
@@ -56,7 +56,7 @@
     visibility = ["//visibility:public"],
     exports = [
         ":io",
-        "@jetty_http//jar",
+        "@jetty-http//jar",
     ],
 )
 
@@ -65,12 +65,12 @@
     data = ["//lib:LICENSE-Apache2.0"],
     exports = [
         ":util",
-        "@jetty_io//jar",
+        "@jetty-io//jar",
     ],
 )
 
 java_library(
     name = "util",
     data = ["//lib:LICENSE-Apache2.0"],
-    exports = ["@jetty_util//jar"],
+    exports = ["@jetty-util//jar"],
 )
diff --git a/lib/jgit/jgit.bzl b/lib/jgit/jgit.bzl
index 749fec9..20dbdcb 100644
--- a/lib/jgit/jgit.bzl
+++ b/lib/jgit/jgit.bzl
@@ -23,7 +23,7 @@
 
 def jgit_maven_repos():
     maven_jar(
-        name = "jgit_lib",
+        name = "jgit-lib",
         artifact = "org.eclipse.jgit:org.eclipse.jgit:" + _JGIT_VERS,
         repository = _JGIT_REPO,
         sha1 = "265a39c017ecfeed7e992b6aaa336e515bf6e157",
@@ -31,20 +31,20 @@
         unsign = True,
     )
     maven_jar(
-        name = "jgit_servlet",
+        name = "jgit-servlet",
         artifact = "org.eclipse.jgit:org.eclipse.jgit.http.server:" + _JGIT_VERS,
         repository = _JGIT_REPO,
         sha1 = "0d68f62286b5db759fdbeb122c789db1f833a06a",
         unsign = True,
     )
     maven_jar(
-        name = "jgit_archive",
+        name = "jgit-archive",
         artifact = "org.eclipse.jgit:org.eclipse.jgit.archive:" + _JGIT_VERS,
         repository = _JGIT_REPO,
         sha1 = "4cc3ed2c42ee63593fd1b16215fcf13eeefb833e",
     )
     maven_jar(
-        name = "jgit_junit",
+        name = "jgit-junit",
         artifact = "org.eclipse.jgit:org.eclipse.jgit.junit:" + _JGIT_VERS,
         repository = _JGIT_REPO,
         sha1 = "6f1bcc9ac22b31b5a6e1e68c08283850108b900c",
@@ -53,11 +53,11 @@
 
 def jgit_dep(name):
   mapping = {
-      "@jgit_junit//jar": "@jgit//org.eclipse.jgit.junit:junit",
-      "@jgit_lib//jar:src": "@jgit//org.eclipse.jgit:libjgit-src.jar",
-      "@jgit_lib//jar": "@jgit//org.eclipse.jgit:jgit",
-      "@jgit_servlet//jar":"@jgit//org.eclipse.jgit.http.server:jgit-servlet",
-      "@jgit_archive//jar": "@jgit//org.eclipse.jgit.archive:jgit-archive",
+      "@jgit-junit//jar": "@jgit//org.eclipse.jgit.junit:junit",
+      "@jgit-lib//jar:src": "@jgit//org.eclipse.jgit:libjgit-src.jar",
+      "@jgit-lib//jar": "@jgit//org.eclipse.jgit:jgit",
+      "@jgit-servlet//jar":"@jgit//org.eclipse.jgit.http.server:jgit-servlet",
+      "@jgit-archive//jar": "@jgit//org.eclipse.jgit.archive:jgit-archive",
   }
 
   if LOCAL_JGIT_REPO:
diff --git a/lib/jgit/org.eclipse.jgit.archive/BUILD b/lib/jgit/org.eclipse.jgit.archive/BUILD
index 198ff25..2742623 100644
--- a/lib/jgit/org.eclipse.jgit.archive/BUILD
+++ b/lib/jgit/org.eclipse.jgit.archive/BUILD
@@ -4,6 +4,6 @@
     name = "jgit-archive",
     data = ["//lib:LICENSE-jgit"],
     visibility = ["//visibility:public"],
-    exports = [jgit_dep("@jgit_archive//jar")],
+    exports = [jgit_dep("@jgit-archive//jar")],
     runtime_deps = ["//lib/jgit/org.eclipse.jgit:jgit"],
 )
diff --git a/lib/jgit/org.eclipse.jgit.http.server/BUILD b/lib/jgit/org.eclipse.jgit.http.server/BUILD
index 6b5bf78..001ad8b 100644
--- a/lib/jgit/org.eclipse.jgit.http.server/BUILD
+++ b/lib/jgit/org.eclipse.jgit.http.server/BUILD
@@ -4,6 +4,6 @@
     name = "jgit-servlet",
     data = ["//lib:LICENSE-jgit"],
     visibility = ["//visibility:public"],
-    exports = [jgit_dep("@jgit_servlet//jar")],
+    exports = [jgit_dep("@jgit-servlet//jar")],
     runtime_deps = ["//lib/jgit/org.eclipse.jgit:jgit"],
 )
diff --git a/lib/jgit/org.eclipse.jgit.junit/BUILD b/lib/jgit/org.eclipse.jgit.junit/BUILD
index ba6c42f..85e9167 100644
--- a/lib/jgit/org.eclipse.jgit.junit/BUILD
+++ b/lib/jgit/org.eclipse.jgit.junit/BUILD
@@ -5,6 +5,6 @@
     testonly = 1,
     data = ["//lib:LICENSE-DO_NOT_DISTRIBUTE"],
     visibility = ["//visibility:public"],
-    exports = [jgit_dep("@jgit_junit//jar")],
+    exports = [jgit_dep("@jgit-junit//jar")],
     runtime_deps = ["//lib/jgit/org.eclipse.jgit:jgit"],
 )
diff --git a/lib/jgit/org.eclipse.jgit/BUILD b/lib/jgit/org.eclipse.jgit/BUILD
index caf8eec..d61ac93 100644
--- a/lib/jgit/org.eclipse.jgit/BUILD
+++ b/lib/jgit/org.eclipse.jgit/BUILD
@@ -4,7 +4,7 @@
     name = "jgit",
     data = ["//lib:LICENSE-jgit"],
     visibility = ["//visibility:public"],
-    exports = [jgit_dep("@jgit_lib//jar")],
+    exports = [jgit_dep("@jgit-lib//jar")],
     runtime_deps = [
         ":javaewah",
         "//lib/log:api",
@@ -13,7 +13,7 @@
 
 alias(
     name = "jgit-source",
-    actual = jgit_dep("@jgit_lib//jar:src"),
+    actual = jgit_dep("@jgit-lib//jar:src"),
     visibility = ["//visibility:public"],
 )
 
diff --git a/lib/log/BUILD b/lib/log/BUILD
index 949260d..8e4c927 100644
--- a/lib/log/BUILD
+++ b/lib/log/BUILD
@@ -5,21 +5,21 @@
         "//lib/jgit/org.eclipse.jgit:__pkg__",
         "//plugins:__pkg__",
     ],
-    exports = ["@log_api//jar"],
+    exports = ["@log-api//jar"],
 )
 
 java_library(
     name = "ext",
     data = ["//lib:LICENSE-slf4j"],
     visibility = ["//visibility:public"],
-    exports = ["@log_ext//jar"],
+    exports = ["@log-ext//jar"],
 )
 
 java_library(
-    name = "impl_log4j",
+    name = "impl-log4j",
     data = ["//lib:LICENSE-slf4j"],
     visibility = ["//visibility:public"],
-    exports = ["@impl_log4j//jar"],
+    exports = ["@impl-log4j//jar"],
     runtime_deps = [":log4j"],
 )
 
@@ -27,7 +27,7 @@
     name = "jcl-over-slf4j",
     data = ["//lib:LICENSE-slf4j"],
     visibility = ["//visibility:public"],
-    exports = ["@jcl_over_slf4j//jar"],
+    exports = ["@jcl-over-slf4j//jar"],
 )
 
 java_library(
@@ -41,7 +41,7 @@
     name = "jsonevent-layout",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@jsonevent_layout//jar"],
+    exports = ["@jsonevent-layout//jar"],
     runtime_deps = [
         ":json-smart",
         "//lib/commons:lang",
@@ -52,5 +52,5 @@
     name = "json-smart",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@json_smart//jar"],
+    exports = ["@json-smart//jar"],
 )
diff --git a/lib/lucene/BUILD b/lib/lucene/BUILD
index 5c8982a..421caed 100644
--- a/lib/lucene/BUILD
+++ b/lib/lucene/BUILD
@@ -7,8 +7,8 @@
 merge_maven_jars(
     name = "lucene-core-and-backward-codecs",
     srcs = [
-        "@backward_codecs//jar",
-        "@lucene_core//jar",
+        "@backward-codecs//jar",
+        "@lucene-core//jar",
     ],
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
@@ -18,7 +18,7 @@
     name = "lucene-analyzers-common",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@lucene_analyzers_common//jar"],
+    exports = ["@lucene-analyzers-common//jar"],
     runtime_deps = [":lucene-core-and-backward-codecs"],
 )
 
@@ -26,14 +26,14 @@
     name = "lucene-core",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@lucene_core//jar"],
+    exports = ["@lucene-core//jar"],
 )
 
 java_library(
     name = "lucene-misc",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@lucene_misc//jar"],
+    exports = ["@lucene-misc//jar"],
     runtime_deps = [":lucene-core-and-backward-codecs"],
 )
 
@@ -41,6 +41,6 @@
     name = "lucene-queryparser",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@lucene_queryparser//jar"],
+    exports = ["@lucene-queryparser//jar"],
     runtime_deps = [":lucene-core-and-backward-codecs"],
 )
diff --git a/lib/mime4j/BUILD b/lib/mime4j/BUILD
index e7b85ef..ee407c3 100644
--- a/lib/mime4j/BUILD
+++ b/lib/mime4j/BUILD
@@ -2,12 +2,12 @@
     name = "core",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@mime4j_core//jar"],
+    exports = ["@mime4j-core//jar"],
 )
 
 java_library(
     name = "dom",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@mime4j_dom//jar"],
+    exports = ["@mime4j-dom//jar"],
 )
diff --git a/lib/mina/BUILD b/lib/mina/BUILD
index 66a0960..8595bb5 100644
--- a/lib/mina/BUILD
+++ b/lib/mina/BUILD
@@ -22,5 +22,5 @@
     name = "core",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@mina_core//jar"],
+    exports = ["@mina-core//jar"],
 )
diff --git a/lib/openid/BUILD b/lib/openid/BUILD
index 2b36fbb..faa073b 100644
--- a/lib/openid/BUILD
+++ b/lib/openid/BUILD
@@ -2,7 +2,7 @@
     name = "consumer",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = ["//visibility:public"],
-    exports = ["@openid_consumer//jar"],
+    exports = ["@openid-consumer//jar"],
     runtime_deps = [
         ":nekohtml",
         ":xerces",
diff --git a/lib/ow2/BUILD b/lib/ow2/BUILD
index aebca49..5a82572 100644
--- a/lib/ow2/BUILD
+++ b/lib/ow2/BUILD
@@ -2,21 +2,21 @@
     name = "ow2-asm",
     data = ["//lib:LICENSE-ow2"],
     visibility = ["//visibility:public"],
-    exports = ["@ow2_asm//jar"],
+    exports = ["@ow2-asm//jar"],
 )
 
 java_library(
     name = "ow2-asm-analysis",
     data = ["//lib:LICENSE-ow2"],
     visibility = ["//visibility:public"],
-    exports = ["@ow2_asm_analysis//jar"],
+    exports = ["@ow2-asm-analysis//jar"],
 )
 
 java_library(
     name = "ow2-asm-commons",
     data = ["//lib:LICENSE-ow2"],
     visibility = ["//visibility:public"],
-    exports = ["@ow2_asm_commons//jar"],
+    exports = ["@ow2-asm-commons//jar"],
     runtime_deps = [":ow2-asm-tree"],
 )
 
@@ -24,12 +24,12 @@
     name = "ow2-asm-tree",
     data = ["//lib:LICENSE-ow2"],
     visibility = ["//visibility:public"],
-    exports = ["@ow2_asm_tree//jar"],
+    exports = ["@ow2-asm-tree//jar"],
 )
 
 java_library(
     name = "ow2-asm-util",
     data = ["//lib:LICENSE-ow2"],
     visibility = ["//visibility:public"],
-    exports = ["@ow2_asm_util//jar"],
+    exports = ["@ow2-asm-util//jar"],
 )
diff --git a/lib/powermock/BUILD b/lib/powermock/BUILD
index 7353b56..57880f4 100644
--- a/lib/powermock/BUILD
+++ b/lib/powermock/BUILD
@@ -5,7 +5,7 @@
     exports = [
         ":powermock-module-junit4-common",
         "//lib:junit",
-        "@powermock_module_junit4//jar",
+        "@powermock-module-junit4//jar",
     ],
 )
 
@@ -16,7 +16,7 @@
     exports = [
         ":powermock-reflect",
         "//lib:junit",
-        "@powermock_module_junit4_common//jar",
+        "@powermock-module-junit4-common//jar",
     ],
 )
 
@@ -27,7 +27,7 @@
     exports = [
         "//lib:junit",
         "//lib/easymock:objenesis",
-        "@powermock_reflect//jar",
+        "@powermock-reflect//jar",
     ],
 )
 
@@ -38,7 +38,7 @@
     exports = [
         ":powermock-api-support",
         "//lib/easymock",
-        "@powermock_api_easymock//jar",
+        "@powermock-api-easymock//jar",
     ],
 )
 
@@ -50,7 +50,7 @@
         ":powermock-core",
         ":powermock-reflect",
         "//lib:junit",
-        "@powermock_api_support//jar",
+        "@powermock-api-support//jar",
     ],
 )
 
@@ -62,6 +62,6 @@
         ":powermock-reflect",
         "//lib:javassist",
         "//lib:junit",
-        "@powermock_core//jar",
+        "@powermock-core//jar",
     ],
 )
diff --git a/lib/prolog/BUILD b/lib/prolog/BUILD
index f6b4c5f..8518af7 100644
--- a/lib/prolog/BUILD
+++ b/lib/prolog/BUILD
@@ -2,21 +2,21 @@
     name = "runtime",
     data = ["//lib:LICENSE-prologcafe"],
     visibility = ["//visibility:public"],
-    exports = ["@prolog_runtime//jar"],
+    exports = ["@prolog-runtime//jar"],
 )
 
 java_library(
     name = "runtime-neverlink",
     data = ["//lib:LICENSE-prologcafe"],
     visibility = ["//visibility:public"],
-    exports = ["@prolog_runtime//jar:neverlink"],
+    exports = ["@prolog-runtime//jar:neverlink"],
 )
 
 java_library(
     name = "compiler",
     data = ["//lib:LICENSE-prologcafe"],
     visibility = ["//visibility:public"],
-    exports = ["@prolog_compiler//jar"],
+    exports = ["@prolog-compiler//jar"],
     runtime_deps = [
         ":io",
         ":runtime",
@@ -26,7 +26,7 @@
 java_library(
     name = "io",
     data = ["//lib:LICENSE-prologcafe"],
-    exports = ["@prolog_io//jar"],
+    exports = ["@prolog-io//jar"],
 )
 
 java_library(
@@ -41,14 +41,14 @@
 )
 
 java_binary(
-    name = "compiler_bin",
+    name = "compiler-bin",
     main_class = "BuckPrologCompiler",
     visibility = ["//visibility:public"],
-    runtime_deps = [":compiler_lib"],
+    runtime_deps = [":compiler-lib"],
 )
 
 java_library(
-    name = "compiler_lib",
+    name = "compiler-lib",
     srcs = ["java/BuckPrologCompiler.java"],
     visibility = ["//visibility:public"],
     deps = [
diff --git a/lib/prolog/prolog.bzl b/lib/prolog/prolog.bzl
index 43a8bab..d905ad8 100644
--- a/lib/prolog/prolog.bzl
+++ b/lib/prolog/prolog.bzl
@@ -19,11 +19,11 @@
     **kwargs):
   native.genrule(
     name = name + '__pl2j',
-    cmd = '$(location //lib/prolog:compiler_bin) ' +
+    cmd = '$(location //lib/prolog:compiler-bin) ' +
       '$$(dirname $@) $@ ' +
       '$(SRCS)',
     srcs = srcs,
-    tools = ['//lib/prolog:compiler_bin'],
+    tools = ['//lib/prolog:compiler-bin'],
     outs = [ name + '.srcjar' ],
   )
   native.java_library(
diff --git a/lib/testcontainers/BUILD b/lib/testcontainers/BUILD
index e6ec04f..f99365d 100644
--- a/lib/testcontainers/BUILD
+++ b/lib/testcontainers/BUILD
@@ -3,7 +3,7 @@
     testonly = True,
     data = ["//lib:LICENSE-testcontainers"],
     visibility = ["//visibility:public"],
-    exports = ["@duct_tape//jar"],
+    exports = ["@duct-tape//jar"],
 )
 
 java_library(
@@ -11,7 +11,7 @@
     testonly = True,
     data = ["//lib:LICENSE-testcontainers"],
     visibility = ["//visibility:public"],
-    exports = ["@visible_assertions//jar"],
+    exports = ["@visible-assertions//jar"],
 )
 
 java_library(
diff --git a/plugins/BUILD b/plugins/BUILD
index 7252f8c..aa98e72 100644
--- a/plugins/BUILD
+++ b/plugins/BUILD
@@ -36,7 +36,7 @@
     "//java/com/google/gerrit/metrics",
     "//java/com/google/gerrit/metrics/dropwizard",
     "//java/com/google/gerrit/reviewdb:server",
-    "//java/com/google/gwtexpui/server",
+    "//java/com/google/gerrit/util/http",
     "//lib/commons:dbcp",
     "//lib/commons:lang",
     "//lib/commons:lang3",
@@ -45,7 +45,7 @@
     "//lib/guice:guice",
     "//lib/guice:guice-assistedinject",
     "//lib/guice:guice-servlet",
-    "//lib/guice:javax-inject",
+    "//lib/guice:javax_inject",
     "//lib/httpcomponents:httpclient",
     "//lib/httpcomponents:httpcore",
     "//lib/jackson:jackson-core",
@@ -110,7 +110,7 @@
         "//java/com/google/gerrit/server:libserver-src.jar",
         "//java/com/google/gerrit/server/restapi:librestapi-src.jar",
         "//java/com/google/gerrit/sshd:libsshd-src.jar",
-        "//java/com/google/gwtexpui/server:libserver-src.jar",
+        "//java/com/google/gerrit/util/http:libhttp-src.jar",
     ],
 )
 
@@ -125,8 +125,8 @@
         "//java/com/google/gerrit/common:annotations",
         "//java/com/google/gerrit/common:server",
         "//java/com/google/gerrit/extensions:api",
-        "//java/com/google/gwtexpui/server",
         "//java/com/google/gerrit/reviewdb:server",
+        "//java/com/google/gerrit/util/http",
     ],
     pkgs = ["com.google.gerrit"],
     title = "Gerrit Review Plugin API Documentation",
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.html b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.html
index 431d56f4..f8c1ff4 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.html
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.html
@@ -71,29 +71,30 @@
       #moreActions iron-icon {
         margin: 0;
       }
+      #moreMessage,
       .hidden {
         display: none;
       }
       @media screen and (max-width: 50em) {
-        #mainContent,
-        section,
-        gr-button,
-        gr-dropdown {
-          display: block;
-          flex: 1;
+        #mainContent {
+          flex-wrap: wrap;
+        }
+        gr-button {
+          --gr-button: {
+            padding: .5em;
+            white-space: nowrap;
+          }
         }
         gr-button,
         gr-dropdown {
-          /* px because don't have the same font size */
-          margin: 0 0 6px 0;
+          margin: 0;
         }
         #actionLoadingMessage {
-          display: block;
           margin: .5em;
           text-align: center;
         }
-        #mainContent.mobileOverlayOpened {
-          display: none;
+        #moreMessage {
+          display: inline;
         }
       }
     </style>
@@ -154,6 +155,7 @@
           disabled-ids="[[_disabledMenuActions]]"
           items="[[_menuActions]]">
           <iron-icon icon="gr-icons:more-vert"></iron-icon>
+          <span id="moreMessage">More</span>
         </gr-dropdown>
     </div>
     <gr-overlay id="overlay" with-backdrop>
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 7ae2ef6..d9da343 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
@@ -391,7 +391,7 @@
       '_actionsChanged(actions.*, revisionActions.*, _additionalActions.*)',
       '_changeChanged(change)',
       '_editStatusChanged(editMode, editPatchsetLoaded, ' +
-          'editBasedOnCurrentPatchSet, actions.*, change)',
+          'editBasedOnCurrentPatchSet, actions.*, change.*)',
     ],
 
     listeners: {
@@ -558,73 +558,63 @@
       }
     },
 
+      /**
+       * @param {string=} actionName
+       */
+    _deleteAndNotify(actionName) {
+      if (this.actions[actionName]) {
+        delete this.actions[actionName];
+        this.notifyPath('actions.' + actionName);
+      }
+    },
+
     _editStatusChanged(editMode, editPatchsetLoaded,
         editBasedOnCurrentPatchSet) {
-      const changeActions = this.actions;
-
       if (editPatchsetLoaded) {
         // Only show actions that mutate an edit if an actual edit patch set
         // is loaded.
         if (this.changeIsOpen(this.change.status)) {
           if (editBasedOnCurrentPatchSet) {
-            if (!changeActions.publishEdit) {
+            if (!this.actions.publishEdit) {
               this.set('actions.publishEdit', PUBLISH_EDIT);
             }
-            if (changeActions.rebaseEdit) {
-              delete this.actions.rebaseEdit;
-              this.notifyPath('actions.rebaseEdit');
-            }
+            this._deleteAndNotify('rebaseEdit');
           } else {
-            if (!changeActions.rebaseEdit) {
+            if (!this.actions.rebaseEdit) {
               this.set('actions.rebaseEdit', REBASE_EDIT);
             }
-            if (changeActions.publishEdit) {
-              delete this.actions.publishEdit;
-              this.notifyPath('actions.publishEdit');
-            }
+            this._deleteAndNotify('publishEdit');
           }
         }
-        if (!changeActions.deleteEdit) {
+        if (!this.actions.deleteEdit) {
           this.set('actions.deleteEdit', DELETE_EDIT);
         }
       } else {
-        if (changeActions.publishEdit) {
-          delete this.actions.publishEdit;
-          this.notifyPath('actions.publishEdit');
-        }
-        if (changeActions.rebaseEdit) {
-          delete this.actions.rebaseEdit;
-          this.notifyPath('actions.rebaseEdit');
-        }
-        if (changeActions.deleteEdit) {
-          delete this.actions.deleteEdit;
-          this.notifyPath('actions.deleteEdit');
-        }
+        this._deleteAndNotify('publishEdit');
+        this._deleteAndNotify('rebaseEdit');
+        this._deleteAndNotify('deleteEdit');
       }
 
       if (this.changeIsOpen(this.change.status)) {
         // Only show edit button if there is no edit patchset loaded and the
         // file list is not in edit mode.
         if (editPatchsetLoaded || editMode) {
-          if (changeActions.edit) {
-            delete this.actions.edit;
-            this.notifyPath('actions.edit');
-          }
+          this._deleteAndNotify('edit');
         } else {
-          if (!changeActions.edit) { this.set('actions.edit', EDIT); }
+          if (!this.actions.edit) { this.set('actions.edit', EDIT); }
         }
         // Only show STOP_EDIT if edit mode is enabled, but no edit patch set
         // is loaded.
         if (editMode && !editPatchsetLoaded) {
-          if (!changeActions.stopEdit) {
+          if (!this.actions.stopEdit) {
             this.set('actions.stopEdit', STOP_EDIT);
           }
         } else {
-          if (changeActions.stopEdit) {
-            delete this.actions.stopEdit;
-            this.notifyPath('actions.stopEdit');
-          }
+          this._deleteAndNotify('stopEdit');
         }
+      } else {
+        // Remove edit button.
+        this._deleteAndNotify('edit');
       }
     },
 
@@ -1119,8 +1109,7 @@
     _setLabelValuesOnRevert(newChangeId) {
       const labels = this.$.jsAPI.getLabelValuesPostRevert(this.change);
       if (!labels) { return Promise.resolve(); }
-      return this.$.restAPI.getChangeURLAndSend(newChangeId,
-          this.actions.revert.method, 'current', '/review', {labels});
+      return this.$.restAPI.saveChangeReview(newChangeId, 'current', {labels});
     },
 
     _handleResponse(action, response) {
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
index f8c522d..1c841f1 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
@@ -401,6 +401,19 @@
       assert.isFalse(element.$.mainContent.classList.contains('overlayOpen'));
     });
 
+    test('_setLabelValuesOnRevert', () => {
+      const labels = {'Foo': 1, 'Bar-Baz': -2};
+      const changeId = 1234;
+      sandbox.stub(element.$.jsAPI, 'getLabelValuesPostRevert').returns(labels);
+      const saveStub = sandbox.stub(element.$.restAPI, 'saveChangeReview')
+          .returns(Promise.resolve());
+      return element._setLabelValuesOnRevert(changeId).then(() => {
+        assert.isTrue(saveStub.calledOnce);
+        assert.equal(saveStub.lastCall.args[0], changeId);
+        assert.deepEqual(saveStub.lastCall.args[2], {labels});
+      });
+    });
+
     suite('change edits', () => {
       test('shows confirm dialog for delete edit', () => {
         element.set('editMode', true);
@@ -490,6 +503,11 @@
 
         assert.isNotOk(element.$$('gr-button[data-action-key="edit"]'));
         assert.isOk(element.$$('gr-button[data-action-key="stopEdit"]'));
+        element.change = {status: 'MERGED'};
+        flushAsynchronousOperations();
+
+        assert.isNotOk(element.$$('gr-button[data-action-key="edit"]'));
+        element.change = {status: 'NEW'};
         element.set('editMode', false);
         flushAsynchronousOperations();
 
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html
index 3f26628..41e5227 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html
@@ -312,16 +312,16 @@
             </span>
             <div class="comments desktop">
               <span class="drafts">
-                [[_computeDraftsString(changeComments, patchRange.patchNum, file.__path)]]
+                [[_computeDraftsString(changeComments, patchRange, file.__path)]]
               </span>
-              [[_computeCommentsString(changeComments, patchRange.patchNum, file.__path)]]
+              [[_computeCommentsString(changeComments, patchRange, file.__path)]]
             </div>
             <div class="comments mobile">
               <span class="drafts">
-                [[_computeDraftsStringMobile(changeComments, patchRange.patchNum,
+                [[_computeDraftsStringMobile(changeComments, patchRange,
                     file.__path)]]
               </span>
-              [[_computeCommentsStringMobile(changeComments, patchRange.patchNum,
+              [[_computeCommentsStringMobile(changeComments, patchRange,
                   file.__path)]]
             </div>
             <div class$="[[_computeSizeBarsClass(_showSizeBars, file.__path)]]">
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 c5ba182..e27a8ea 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
@@ -381,14 +381,17 @@
      * Computes a string with the number of comments and unresolved comments.
      *
      * @param {!Object} changeComments
-     * @param {number} patchNum
+     * @param {!Object} patchRange
      * @param {string} path
      * @return {string}
      */
-    _computeCommentsString(changeComments, patchNum, path) {
-      const unresolvedCount = changeComments.computeUnresolvedNum(patchNum,
-          path);
-      const commentCount = changeComments.computeCommentCount(patchNum, path);
+    _computeCommentsString(changeComments, patchRange, path) {
+      const unresolvedCount =
+          changeComments.computeUnresolvedNum(patchRange.basePatchNum, path) +
+          changeComments.computeUnresolvedNum(patchRange.patchNum, path);
+      const commentCount =
+          changeComments.computeCommentCount(patchRange.basePatchNum, path) +
+          changeComments.computeCommentCount(patchRange.patchNum, path);
       const commentString = GrCountStringFormatter.computePluralString(
           commentCount, 'comment');
       const unresolvedString = GrCountStringFormatter.computeString(
@@ -405,12 +408,14 @@
      * Computes a string with the number of drafts.
      *
      * @param {!Object} changeComments
-     * @param {number} patchNum
+     * @param {!Object} patchRange
      * @param {string} path
      * @return {string}
      */
-    _computeDraftsString(changeComments, patchNum, path) {
-      const draftCount = changeComments.computeDraftCount(patchNum, path);
+    _computeDraftsString(changeComments, patchRange, path) {
+      const draftCount =
+          changeComments.computeDraftCount(patchRange.basePatchNum, path) +
+          changeComments.computeDraftCount(patchRange.patchNum, path);
       return GrCountStringFormatter.computePluralString(draftCount, 'draft');
     },
 
@@ -418,12 +423,14 @@
      * Computes a shortened string with the number of drafts.
      *
      * @param {!Object} changeComments
-     * @param {number} patchNum
+     * @param {!Object} patchRange
      * @param {string} path
      * @return {string}
      */
-    _computeDraftsStringMobile(changeComments, patchNum, path) {
-      const draftCount = changeComments.computeDraftCount(patchNum, path);
+    _computeDraftsStringMobile(changeComments, patchRange, path) {
+      const draftCount =
+          changeComments.computeDraftCount(patchRange.basePatchNum, path) +
+          changeComments.computeDraftCount(patchRange.patchNum, path);
       return GrCountStringFormatter.computeShortString(draftCount, 'd');
     },
 
@@ -431,12 +438,14 @@
      * Computes a shortened string with the number of comments.
      *
      * @param {!Object} changeComments
-     * @param {number} patchNum
+     * @param {!Object} patchRange
      * @param {string} path
      * @return {string}
      */
-    _computeCommentsStringMobile(changeComments, patchNum, path) {
-      const commentCount = changeComments.computeCommentCount(patchNum, path);
+    _computeCommentsStringMobile(changeComments, patchRange, path) {
+      const commentCount =
+          changeComments.computeCommentCount(patchRange.basePatchNum, path) +
+          changeComments.computeCommentCount(patchRange.patchNum, path);
       return GrCountStringFormatter.computeShortString(commentCount, 'c');
     },
 
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
index 277d005..5833a9a 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
@@ -391,68 +391,147 @@
         ],
       };
 
+      const parentTo1 = {
+        basePatchNum: 'PARENT',
+        patchNum: '1',
+      };
+
+      const parentTo2 = {
+        basePatchNum: 'PARENT',
+        patchNum: '2',
+      };
+
+      const _1To2 = {
+        basePatchNum: '1',
+        patchNum: '2',
+      };
+
       assert.equal(
-          element._computeCommentsString(element.changeComments, '1',
+          element._computeCommentsString(element.changeComments, parentTo1,
               '/COMMIT_MSG', 'comment'), '2 comments (1 unresolved)');
       assert.equal(
-          element._computeCommentsStringMobile(element.changeComments, '1'
+          element._computeCommentsString(element.changeComments, _1To2,
+              '/COMMIT_MSG', 'comment'), '3 comments (1 unresolved)');
+      assert.equal(
+          element._computeCommentsStringMobile(element.changeComments, parentTo1
           , '/COMMIT_MSG'), '2c');
       assert.equal(
-          element._computeDraftsString(element.changeComments, '1',
+          element._computeCommentsStringMobile(element.changeComments, _1To2
+          , '/COMMIT_MSG'), '3c');
+      assert.equal(
+          element._computeDraftsString(element.changeComments, parentTo1,
               'unresolved.file'), '1 draft');
       assert.equal(
-          element._computeDraftsStringMobile(element.changeComments, '1',
+          element._computeDraftsString(element.changeComments, _1To2,
+              'unresolved.file'), '1 draft');
+      assert.equal(
+          element._computeDraftsStringMobile(element.changeComments, parentTo1,
               'unresolved.file'), '1d');
       assert.equal(
-          element._computeCommentsString(element.changeComments, '1',
+          element._computeDraftsStringMobile(element.changeComments, _1To2,
+              'unresolved.file'), '1d');
+      assert.equal(
+          element._computeCommentsString(element.changeComments, parentTo1,
               'myfile.txt', 'comment'), '1 comment');
       assert.equal(
-          element._computeCommentsStringMobile(element.changeComments, '1',
+          element._computeCommentsString(element.changeComments, _1To2,
+              'myfile.txt', 'comment'), '3 comments');
+      assert.equal(
+          element._computeCommentsStringMobile(element.changeComments, parentTo1,
               'myfile.txt'), '1c');
       assert.equal(
-          element._computeDraftsString(element.changeComments, '1',
+          element._computeCommentsStringMobile(element.changeComments, _1To2,
+              'myfile.txt'), '3c');
+      assert.equal(
+          element._computeDraftsString(element.changeComments, parentTo1,
               'myfile.txt'), '');
       assert.equal(
-          element._computeDraftsStringMobile(element.changeComments, '1',
+          element._computeDraftsString(element.changeComments, _1To2,
               'myfile.txt'), '');
       assert.equal(
-          element._computeCommentsString(element.changeComments, '1',
+          element._computeDraftsStringMobile(element.changeComments, parentTo1,
+              'myfile.txt'), '');
+      assert.equal(
+          element._computeDraftsStringMobile(element.changeComments, _1To2,
+              'myfile.txt'), '');
+      assert.equal(
+          element._computeCommentsString(element.changeComments, parentTo1,
               'file_added_in_rev2.txt', 'comment'), '');
       assert.equal(
-          element._computeCommentsStringMobile(element.changeComments, '1',
+          element._computeCommentsString(element.changeComments, _1To2,
+              'file_added_in_rev2.txt', 'comment'), '');
+      assert.equal(
+          element._computeCommentsStringMobile(element.changeComments, parentTo1,
               'file_added_in_rev2.txt'), '');
       assert.equal(
-          element._computeDraftsString(element.changeComments, '1',
+          element._computeCommentsStringMobile(element.changeComments, _1To2,
               'file_added_in_rev2.txt'), '');
       assert.equal(
-          element._computeDraftsStringMobile(element.changeComments, '1',
+          element._computeDraftsString(element.changeComments, parentTo1,
               'file_added_in_rev2.txt'), '');
       assert.equal(
-          element._computeCommentsString(element.changeComments, '2',
+          element._computeDraftsString(element.changeComments, _1To2,
+              'file_added_in_rev2.txt'), '');
+      assert.equal(
+          element._computeDraftsStringMobile(element.changeComments, parentTo1,
+              'file_added_in_rev2.txt'), '');
+      assert.equal(
+          element._computeDraftsStringMobile(element.changeComments, _1To2,
+              'file_added_in_rev2.txt'), '');
+      assert.equal(
+          element._computeCommentsString(element.changeComments, parentTo2,
               '/COMMIT_MSG', 'comment'), '1 comment');
       assert.equal(
-          element._computeCommentsStringMobile(element.changeComments, '2',
+          element._computeCommentsString(element.changeComments, _1To2,
+              '/COMMIT_MSG', 'comment'), '3 comments (1 unresolved)');
+      assert.equal(
+          element._computeCommentsStringMobile(element.changeComments, parentTo2,
               '/COMMIT_MSG'), '1c');
       assert.equal(
-          element._computeDraftsString(element.changeComments, '1',
+          element._computeCommentsStringMobile(element.changeComments, _1To2,
+              '/COMMIT_MSG'), '3c');
+      assert.equal(
+          element._computeDraftsString(element.changeComments, parentTo1,
               '/COMMIT_MSG'), '2 drafts');
       assert.equal(
-          element._computeDraftsStringMobile(element.changeComments, '1',
+          element._computeDraftsString(element.changeComments, _1To2,
+              '/COMMIT_MSG'), '2 drafts');
+      assert.equal(
+          element._computeDraftsStringMobile(element.changeComments, parentTo1,
               '/COMMIT_MSG'), '2d');
       assert.equal(
-          element._computeCommentsString(element.changeComments, '2',
+          element._computeDraftsStringMobile(element.changeComments, _1To2,
+              '/COMMIT_MSG'), '2d');
+      assert.equal(
+          element._computeCommentsString(element.changeComments, parentTo2,
               'myfile.txt', 'comment'), '2 comments');
       assert.equal(
-          element._computeCommentsStringMobile(element.changeComments, '2',
+          element._computeCommentsString(element.changeComments, _1To2,
+              'myfile.txt', 'comment'), '3 comments');
+      assert.equal(
+          element._computeCommentsStringMobile(element.changeComments, parentTo2,
               'myfile.txt'), '2c');
       assert.equal(
-          element._computeDraftsStringMobile(element.changeComments, '2',
+          element._computeCommentsStringMobile(element.changeComments, _1To2,
+              'myfile.txt'), '3c');
+      assert.equal(
+          element._computeDraftsStringMobile(element.changeComments, parentTo2,
               'myfile.txt'), '');
       assert.equal(
-          element._computeCommentsString(element.changeComments, '2',
+          element._computeDraftsStringMobile(element.changeComments, _1To2,
+              'myfile.txt'), '');
+      assert.equal(
+          element._computeCommentsString(element.changeComments, parentTo2,
               'file_added_in_rev2.txt', 'comment'), '');
-      assert.equal(element._computeCommentsString(element.changeComments, '2',
-          'unresolved.file', 'comment'), '3 comments (1 unresolved)');
+      assert.equal(
+          element._computeCommentsString(element.changeComments, _1To2,
+              'file_added_in_rev2.txt', 'comment'), '');
+      assert.equal(
+          element._computeCommentsString(element.changeComments, parentTo2,
+              'unresolved.file', 'comment'), '3 comments (1 unresolved)');
+      assert.equal(
+          element._computeCommentsString(element.changeComments, _1To2,
+              'unresolved.file', 'comment'), '3 comments (1 unresolved)');
     });
 
     suite('keyboard shortcuts', () => {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-image.js b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-image.js
index fdf18c1..27f8d39 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-image.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-image.js
@@ -52,12 +52,12 @@
     // TODO(kaspern): Support blame for image diffs and remove the hardcoded 4
     // column limit.
     td.setAttribute('colspan', '4');
-
     const endpoint = this._createElement('gr-endpoint-decorator');
-    endpoint.setAttribute('name', 'image-diff');
-    endpoint.appendChild(
+    const endpointDomApi = Polymer.dom(endpoint);
+    endpointDomApi.setAttribute('name', 'image-diff');
+    endpointDomApi.appendChild(
         this._createEndpointParam('baseImage', this._baseImage));
-    endpoint.appendChild(
+    endpointDomApi.appendChild(
         this._createEndpointParam('revisionImage', this._revisionImage));
     td.appendChild(endpoint);
     tr.appendChild(td);
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.js b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.js
index f943b8e..b7d65d3 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.js
+++ b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.js
@@ -92,7 +92,7 @@
 
     _showDropdown() {
       if (this.readOnly || this.editing) { return; }
-      this._open().then(() => {
+      return this._open().then(() => {
         this.$.input.$.input.focus();
         if (!this.$.input.value) { return; }
         this.$.input.$.input.setSelectionRange(0, this.$.input.value.length);
@@ -118,7 +118,7 @@
       let iters = 0;
       const step = () => {
         this.async(() => {
-          if (this.style.display !== 'none') {
+          if (this.$.dropdown.style.display !== 'none') {
             fn.call(this);
           } else if (iters++ < AWAIT_MAX_ITERS) {
             step.call(this);
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.html b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.html
index 058654b..6815173 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.html
@@ -77,14 +77,17 @@
       assert.isFalse(element.$.dropdown.opened);
       assert.isTrue(label.classList.contains('editable'));
       assert.equal(label.textContent, 'value text');
+      const focusSpy = sandbox.spy(element.$.input.$.input, 'focus');
+      const showSpy = sandbox.spy(element, '_showDropdown');
 
       MockInteractions.tap(label);
 
-      Polymer.dom.flush();
-
-      // The dropdown is open (which covers up the label):
-      assert.isTrue(element.$.dropdown.opened);
-      assert.equal(input.value, 'value text');
+      return showSpy.lastCall.returnValue.then(() => {
+        // The dropdown is open (which covers up the label):
+        assert.isTrue(element.$.dropdown.opened);
+        assert.isTrue(focusSpy.called);
+        assert.equal(input.value, 'value text');
+      });
     });
 
     test('title with placeholder', done => {
diff --git a/tools/bzl/pkg_war.bzl b/tools/bzl/pkg_war.bzl
index d6a4c78..46a4f9b 100644
--- a/tools/bzl/pkg_war.bzl
+++ b/tools/bzl/pkg_war.bzl
@@ -23,7 +23,7 @@
     "//lib/bouncycastle:bcpkix",
     "//lib/bouncycastle:bcprov",
     "//lib/bouncycastle:bcpg",
-    "//lib/log:impl_log4j",
+    "//lib/log:impl-log4j",
     "//resources:log4j-config",
 ]
 
diff --git a/tools/eclipse/BUILD b/tools/eclipse/BUILD
index 22c1a80..539423b 100644
--- a/tools/eclipse/BUILD
+++ b/tools/eclipse/BUILD
@@ -31,7 +31,7 @@
     "//lib/gwt:tapestry",
     "//lib/gwt:w3c-css-sac",
     "//lib/jetty:servlets",
-    "//lib/prolog:compiler_lib",
+    "//lib/prolog:compiler-lib",
     # TODO(davido): I do not understand why it must be on the Eclipse classpath
     #'//Documentation:index',
 ]