Merge "Revert "Debounce autocomplete queries by default""
diff --git a/.mailmap b/.mailmap
index bd4d222..f5f8f3e 100644
--- a/.mailmap
+++ b/.mailmap
@@ -11,6 +11,7 @@
 Bruce Zu <bruce.zu.run10@gmail.com>                                                         <bruce.zu@sonymobile.com>
 Carlos Eduardo Baldacin <carloseduardo.baldacin@sonyericsson.com>                           carloseduardo.baldacin <carloseduardo.baldacin@sonyericsson.com>
 Dariusz Luksza <dluksza@collab.net>                                                         <dariusz@luksza.org>
+Dave Borowitz <dborowitz@google.com>                                                        <dborowitz@google.com>
 David Ostrovsky <david@ostrovsky.org>                                                       <d.ostrovsky@gmx.de>
 David Ostrovsky <david@ostrovsky.org>                                                       <david.ostrovsky@gmail.com>
 David Pursehouse <dpursehouse@collab.net>                                                   <david.pursehouse@sonymobile.com>
@@ -43,6 +44,7 @@
 Mark Derricutt <mark.derricutt@smxemail.com>                                                <mark@talios.com>
 Martin Fick <mfick@codeaurora.org>                                                          <mogulguy10@gmail.com>
 Martin Fick <mfick@codeaurora.org>                                                          <mogulguy@yahoo.com>
+Maxime Guerreiro <maximeg@google.com>                                                       <maximeg@google.com>
 Michael Zhou <moz@google.com>                                                               <zhoumotongxue008@gmail.com>
 Mônica Dionísio <monica.dionisio@sonyericsson.com>                                          monica.dionisio <monica.dionisio@sonyericsson.com>
 Nasser Grainawi <nasser@grainawi.org>                                                       <nasser@codeaurora.org>
diff --git a/Documentation/access-control.txt b/Documentation/access-control.txt
index cc03334..72e309a 100644
--- a/Documentation/access-control.txt
+++ b/Documentation/access-control.txt
@@ -859,8 +859,8 @@
 [[category_edit_hashtags]]
 === Edit Hashtags
 
-This category permits users to add or remove hashtags on a change that
-is uploaded for review.
+This category permits users to add or remove
+link:intro-user.html#hashtags[hashtags] on a change that is uploaded for review.
 
 The change owner, branch owners, project owners, and site administrators
 can always edit or remove hashtags (even without having the `Edit Hashtags`
diff --git a/Documentation/cmd-stream-events.txt b/Documentation/cmd-stream-events.txt
index ba346e7..a75f610 100644
--- a/Documentation/cmd-stream-events.txt
+++ b/Documentation/cmd-stream-events.txt
@@ -151,7 +151,8 @@
 
 === Hashtags Changed
 
-Sent when the hashtags have been added to or removed from a change.
+Sent when the link:intro-user.html#hashtags[hashtags] have been added to or
+removed from a change.
 
 type:: "hashtags-changed"
 
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 1b6d116..de73930 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -2144,6 +2144,15 @@
 Path for PolyGerrit's favicon after link:#gerrit.canonicalWebUrl[default URL],
 including icon name and extension (.ico should be used).
 
+
+[[gerrit.instanceName]]gerrit.instanceName::
++
+Short identifier for this Gerrit instance.
+A good name should be short but precise enough so that users can identify the instance among others.
++
+Defaults to the full hostname of the Gerrit server.
+
+
 [[gerrit.ui]]gerrit.ui::
 +
 Default UI when the user does not request a different preference via argument
@@ -2702,6 +2711,10 @@
 limit will truncate the list (but will still set `_more_changes` on
 result lists). Set to 0 for no limit.
 +
+When `index.type` is set to `ELASTICSEARCH`, this value should not exceed
+the `index.max_result_window` value configured on the Elasticsearch
+server.
++
 Defaults to no limit.
 
 [[index.maxPages]]index.maxPages::
@@ -4123,6 +4136,17 @@
 +
 Defaults to an empty list, meaning no additional TLDs are allowed.
 
+
+[[sendemail.addInstanceNameInSubject]]sendemail.addInstanceNameInSubject::
++
+When set to true, Gerrit will add its short name to the email subject, allowing recipients to quickly identify
+what Gerrit instance the email came from.
++
+The short name can be customized via the gerrit.instanceName option.
++
+Defaults to true.
+
+
 [[site]]
 === Section site
 
diff --git a/Documentation/config-gitweb.txt b/Documentation/config-gitweb.txt
index fcfd0e1..d49acfee 100644
--- a/Documentation/config-gitweb.txt
+++ b/Documentation/config-gitweb.txt
@@ -17,8 +17,9 @@
 Linux distributions.
 
 ----
-  git config --file $site_path/etc/gerrit.config gitweb.cgi /usr/lib/cgi-bin/gitweb.cgi
-  git config --file $site_path/etc/gerrit.config --unset gitweb.url
+  git config -f $site_path/etc/gerrit.config gitweb.type gitweb
+  git config -f $site_path/etc/gerrit.config gitweb.cgi /usr/lib/cgi-bin/gitweb.cgi
+  git config -f $site_path/etc/gerrit.config --unset gitweb.url
 ----
 
 Alternatively, if Gerrit is served behind reverse proxy, it can
@@ -28,8 +29,9 @@
 To enable this feature, set both: `gitweb.cgi` and `gitweb.url`.
 
 ----
-  git config --file $site_path/etc/gerrit.config gitweb.cgi /usr/lib/cgi-bin/gitweb.cgi
-  git config --file $site_path/etc/gerrit.config gitweb.url /pretty/path/to/gitweb
+  git config -f $site_path/etc/gerrit.config gitweb.type gitweb
+  git config -f $site_path/etc/gerrit.config gitweb.cgi /usr/lib/cgi-bin/gitweb.cgi
+  git config -f $site_path/etc/gerrit.config gitweb.url /pretty/path/to/gitweb
 ----
 
 After updating `'$site_path'/etc/gerrit.config`, the Gerrit server must
@@ -77,13 +79,13 @@
 On Ubuntu:
 
 ----
-  $ sudo apt-get install gitweb
+  sudo apt-get install gitweb
 ----
 
 With Yum:
 
 ----
-  $ yum install gitweb
+  yum install gitweb
 ----
 
 ===== Configure Gitweb
@@ -125,14 +127,14 @@
 Link gitweb to `/var/www/gitweb`, check `/etc/gitweb.conf` if unsure of paths:
 
 ----
-  $ sudo ln -s /usr/share/gitweb /var/www/gitweb
+  sudo ln -s /usr/share/gitweb /var/www/gitweb
 ----
 
 Add the gitweb directory to the Apache configuration by creating a "gitweb"
 file inside the Apache conf.d directory:
 
 ----
-  $ touch /etc/apache/conf.d/gitweb
+  touch /etc/apache/conf.d/gitweb
 ----
 
 Add the following to /etc/apache/conf.d/gitweb:
@@ -152,7 +154,7 @@
 ===== Restart the Apache Web Server
 
 ----
-  $ sudo /etc/init.d/apache2 restart
+  sudo /etc/init.d/apache2 restart
 ----
 
 Now you should be able to view your repository projects online:
@@ -184,7 +186,7 @@
 following to check:
 
 ----
-$ perl -mCGI -mEncode -mFcntl -mFile::Find -mFile::Basename -e ""
+  perl -mCGI -mEncode -mFcntl -mFile::Find -mFile::Basename -e ""
 ----
 
 You may encounter the following exception:
@@ -220,21 +222,22 @@
 namespace is available.
 
 ----
-$ git config -f $site_path/etc/gerrit.config --unset gitweb.cgi
-$ git config -f $site_path/etc/gerrit.config gitweb.url https://gitweb.corporation.com
+  git config -f $site_path/etc/gerrit.config gitweb.type gitweb
+  git config -f $site_path/etc/gerrit.config --unset gitweb.cgi
+  git config -f $site_path/etc/gerrit.config gitweb.url https://gitweb.corporation.com
 ----
 
-If you're not following the traditional \{projectName\}.git project naming conventions,
+If you're not following the traditional `\{projectName\}.git` project naming conventions,
 you will want to customize Gerrit to read them. Add the following:
 
 ----
-$ git config -f $site_path/etc/gerrit.config gitweb.type custom
-$ git config -f $site_path/etc/gerrit.config gitweb.project ?p=\${project}\;a=summary
-$ git config -f $site_path/etc/gerrit.config gitweb.revision ?p=\${project}\;a=commit\;h=\${commit}
-$ git config -f $site_path/etc/gerrit.config gitweb.branch ?p=\${project}\;a=shortlog\;h=\${branch}
-$ git config -f $site_path/etc/gerrit.config gitweb.roottree ?p=\${project}\;a=tree\;hb=\${commit}
-$ git config -f $site_path/etc/gerrit.config gitweb.file ?p=\${project}\;hb=\${commit}\;f=\${file}
-$ git config -f $site_path/etc/gerrit.config gitweb.filehistory ?p=\${project}\;a=history\;hb=\${branch}\;f=\${file}
+  git config -f $site_path/etc/gerrit.config gitweb.type custom
+  git config -f $site_path/etc/gerrit.config gitweb.project ?p=\${project}\;a=summary
+  git config -f $site_path/etc/gerrit.config gitweb.revision ?p=\${project}\;a=commit\;h=\${commit}
+  git config -f $site_path/etc/gerrit.config gitweb.branch ?p=\${project}\;a=shortlog\;h=\${branch}
+  git config -f $site_path/etc/gerrit.config gitweb.roottree ?p=\${project}\;a=tree\;hb=\${commit}
+  git config -f $site_path/etc/gerrit.config gitweb.file ?p=\${project}\;hb=\${commit}\;f=\${file}
+  git config -f $site_path/etc/gerrit.config gitweb.filehistory ?p=\${project}\;a=history\;hb=\${branch}\;f=\${file}
 ----
 
 After updating `'$site_path'/etc/gerrit.config`, the Gerrit server must
diff --git a/Documentation/config-mail.txt b/Documentation/config-mail.txt
index 6bd6b3d..686dfb8 100644
--- a/Documentation/config-mail.txt
+++ b/Documentation/config-mail.txt
@@ -225,6 +225,10 @@
 +
 The project name with the path abbreviated.
 
+$instanceAndProjectName::
++
+The Gerrit instance name, followed by the short project name
+
 $sshHost::
 +
 SSH hostname for the Gerrit instance.
diff --git a/Documentation/config-plugins.txt b/Documentation/config-plugins.txt
index c5f1457..29f3273 100644
--- a/Documentation/config-plugins.txt
+++ b/Documentation/config-plugins.txt
@@ -452,6 +452,14 @@
 link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/metrics-reporter-jmx[
 Project].
 
+[[metrics-reporter-prometheus]]
+=== metrics-reporter-prometheus
+
+This plugin exposes Gerrit metrics for consumption by Prometheus.
+
+link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/metrics-reporter-prometheus[
+Project].
+
 [[motd]]
 === motd
 
diff --git a/Documentation/intro-project-owner.txt b/Documentation/intro-project-owner.txt
index 6056e57..2d0812e 100644
--- a/Documentation/intro-project-owner.txt
+++ b/Documentation/intro-project-owner.txt
@@ -88,7 +88,7 @@
 Normally when a new project is created in Gerrit it already has some
 access rights which are inherited from the parent projects.
 Projects in Gerrit are organized hierarchically as a tree with the
-`All-Projects' project as root from which all projects inherit. Each
+`All-Projects` project as root from which all projects inherit. Each
 project can have only a single parent project, multi-inheritance is
 not supported.
 
@@ -227,12 +227,12 @@
 The different options are described in the
 link:project-configuration.html#project_options[Project Options] section.
 
-To see the options of your project
+To see the options of your project:
 
-- go to the Gerrit Web UI
-- click on the `Projects` > `List` menu entry
-- find your project in the project list and click on it
-- click on the `General` menu entry
+. Go to the Gerrit Web UI.
+. Click on the `Projects` > `List` menu entry.
+. Find your project in the project list and click it.
+. Click the `General` menu entry.
 
 [[submit-type]]
 === Submit Type
@@ -761,11 +761,11 @@
 
 Gerrit core does not support the renaming of projects.
 
-As workaround you may
+As workaround you can perform the following steps:
 
-. link:#project-creation[create a new project] with the new name
-. link:#import-history[import the history of the old project]
-. link:#project-deletion[delete the old project]
+. link:#project-creation[Create a new project] with the new name.
+. link:#import-history[Import the history of the old project].
+. link:#project-deletion[Delete the old project].
 
 Please note that a drawback of this workaround is that the whole review
 history (changes, review comments) is lost.
diff --git a/Documentation/intro-user.txt b/Documentation/intro-user.txt
index 29e02f0..3805c80 100644
--- a/Documentation/intro-user.txt
+++ b/Documentation/intro-user.txt
@@ -472,6 +472,10 @@
 the use of the command line flag `--push-option`, aliased to `-o`,
 followed by `topic=...`.
 
+Gerrit may be link:config-gerrit.html#change.submitWholeTopic[configured] to
+submit all changes in a topic together with a single click, even when topics
+span multiple projects.
+
 .Set Topic on Push
 ----
   $ git push origin HEAD:refs/for/master%topic=multi-master
@@ -480,6 +484,30 @@
   $ git push origin HEAD:refs/heads/master -o topic=multi-master
 ----
 
+[[hashtags]]
+== Using Hashtags
+
+Hashtags are freeform strings associated with a change, like on social media
+platforms. In Gerrit, you explicitly associate hashtags with changes using a
+dedicated area of the UI; they are not parsed from commit messages or comments.
+
+Similar to topics, hashtags can be used to group related changes together, and
+to search using the link:user-search.html#hashtag[`hashtag:`] operator. Unlike
+topics, a change can have multiple hashtags, and they are only used for
+informational grouping; changes with the same hashtags are not necessarily
+submitted together.
+
+The hashtag feature is only available when running under
+link:note-db.html[NoteDb].
+
+.Set Hashtag on Push
+----
+  $ git push origin HEAD:refs/for/master%t=stable-bugfix
+
+  // this is the same as:
+  $ git push origin HEAD:refs/heads/master -o t=stable-bugfix
+----
+
 [[wip]]
 == Work-in-Progress Changes
 
diff --git a/Documentation/pg-plugin-endpoints.txt b/Documentation/pg-plugin-endpoints.txt
index b838e87..d3d0a8d 100644
--- a/Documentation/pg-plugin-endpoints.txt
+++ b/Documentation/pg-plugin-endpoints.txt
@@ -80,3 +80,42 @@
 +
 current comment displayed, an instance of
 link:rest-api-changes.html#comment-info[CommentInfo]
+
+=== repo-command
+This endpoint is situated among the repository commands.
+
+In addition to default parameters, the following are available:
+
+* `repoName`
++
+String name of the repository currently being configured.
+
+* `config`
++
+The object representing the repo config.
+
+=== repo-config
+The `repo-config` extension point is located at the bottom of the repository
+configuration settings screen.
+
+In addition to default parameters, the following are available:
+
+* `repoName`
++
+String name of the repository currently being configured.
+
+=== settings-menu-item
+This endpoint is situated at the end of the navigation menu in the settings
+screen.
+
+=== settings-screen
+This endpoint is situated at the end of the body of the settings screen.
+
+=== reply-text
+This endpoint wraps the textarea in the reply dialog.
+
+=== reply-label-scores
+This endpoint decorator wraps the voting buttons in the reply dialog.
+
+=== header-title
+This endpoint wraps the title-text in the application header.
\ No newline at end of file
diff --git a/Documentation/replace_macros.py b/Documentation/replace_macros.py
index 09e2439..c76d133 100755
--- a/Documentation/replace_macros.py
+++ b/Documentation/replace_macros.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python
 # coding=utf-8
 # Copyright (C) 2013 The Android Open Source Project
 #
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index c1ca595..61edc63 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -785,7 +785,7 @@
   {
     "subject": "Merge dev_branch into master",
     "merge": {
-      "source": "refs/12/1234/1"
+      "source": "refs/changes/34/1234/1"
     }
   }
 ----
@@ -6443,8 +6443,8 @@
 |Field Name      ||Description
 |`source`   ||
 The source to merge from, e.g. a complete or abbreviated commit SHA-1,
-a complete reference name, a short reference name under refs/heads, refs/tags,
-or refs/remotes namespace, etc.
+a complete reference name, a short reference name under `refs/heads`, `refs/tags`,
+or `refs/remotes` namespace, etc.
 |`strategy`     |optional|
 The strategy of the merge, can be `recursive`, `resolve`,
 `simple-two-way-in-core`, `ours` or `theirs`, default will use project settings.
@@ -6653,12 +6653,20 @@
 The `RevertInput` entity contains information for reverting a change.
 
 [options="header",cols="1,^1,5"]
-|===========================
-|Field Name    ||Description
-|`message`     |optional|
+|=============================
+|Field Name      ||Description
+|`message`       |optional|
 Message to be added as review comment to the change when reverting the
 change.
-|===========================
+|`notify`        |optional|
+Notify handling that defines to whom email notifications should be sent
+for reverting the change. +
+Allowed values are `NONE`, `OWNER`, `OWNER_REVIEWERS` and `ALL`. +
+If not set, the default is `ALL`.
+|`notify_details`|optional|
+Additional information about whom to notify about the revert as a map
+of recipient type to link:#notify-info[NotifyInfo] entity.
+|=============================
 
 [[review-info]]
 === ReviewInfo
diff --git a/Documentation/rest-api-groups.txt b/Documentation/rest-api-groups.txt
index a3bcab1..49d5ee5 100644
--- a/Documentation/rest-api-groups.txt
+++ b/Documentation/rest-api-groups.txt
@@ -1518,7 +1518,9 @@
 `REMOVE_USER` the member is returned as detailed
 link:rest-api-accounts.html#account-info[AccountInfo] entity, if `type`
 is `ADD_GROUP` or `REMOVE_GROUP` the member is returned as
-link:#group-info[GroupInfo] entity.
+link:#group-info[GroupInfo] entity. Note that the `name` in
+link:#group-info[GroupInfo] will not be set if the member group is not
+available.
 |`type`    |
 The event type, can be: `ADD_USER`, `REMOVE_USER`, `ADD_GROUP` or
 `REMOVE_GROUP`.
diff --git a/Documentation/user-search-accounts.txt b/Documentation/user-search-accounts.txt
index 04f40c0..6bcd18e 100644
--- a/Documentation/user-search-accounts.txt
+++ b/Documentation/user-search-accounts.txt
@@ -23,6 +23,11 @@
 returned results. Search can also be performed by typing only a
 text with no operator, which will match against a variety of fields.
 
+[[cansee]]
+cansee:'CHANGE'::
++
+Matches accounts that can see the change 'CHANGE'.
+
 [[email]]
 email:'EMAIL'::
 +
diff --git a/Documentation/user-search.txt b/Documentation/user-search.txt
index ba42304..0f030a6 100644
--- a/Documentation/user-search.txt
+++ b/Documentation/user-search.txt
@@ -191,6 +191,11 @@
 often combined with 'branch:' and 'project:' operators to select
 all related changes in a series.
 
+[[hashtag]]
+hashtag:'HASHTAG'::
++
+Changes whose link:intro-user.html#hashtags[hashtag] matches 'HASHTAG' exactly.
+
 [[ref]]
 ref:'REF'::
 +
diff --git a/Documentation/user-upload.txt b/Documentation/user-upload.txt
index 9be39a6..c12a38c 100644
--- a/Documentation/user-upload.txt
+++ b/Documentation/user-upload.txt
@@ -243,12 +243,11 @@
 [[topic]]
 ==== Topic
 
-To include a short tag associated with all of the changes in the
-same group, such as the local topic branch name, append it after
-the destination branch name or add it with the command line flag
-`--push-option`, aliased to `-o`. In this example the short topic
-tag 'driver/i42' will be saved on each change this push creates or
-updates:
+To include a short link:intro-user.html#topics[topic] associated with all
+of the changes in the same group, such as the local topic branch name,
+append it after the destination branch name or add it with the command line
+flag `--push-option`, aliased to `-o`. In this example the short topic name
+'driver/i42' will be saved on each change this push creates or updates:
 
 ----
   git push ssh://john.doe@git.example.com:29418/kernel/common HEAD:refs/for/experimental%topic=driver/i42
@@ -257,6 +256,20 @@
   git push ssh://john.doe@git.example.com:29418/kernel/common HEAD:refs/for/experimental -o topic=driver/i42
 ----
 
+[[hashtag]]
+==== Hashtag
+
+To include a link:intro-user.html#hashtags[hashtag] associated with all of the
+changes in the same group, use the `hashtag` or `t` option:
+
+----
+  // these are all equivalent
+  git push ssh://john.doe@git.example.com:29418/kernel/common HEAD:refs/for/experimental%hashtag=stable-fix
+  git push ssh://john.doe@git.example.com:29418/kernel/common HEAD:refs/for/experimental%t=stable-fix
+  git push ssh://john.doe@git.example.com:29418/kernel/common HEAD:refs/for/experimental -o hashtag=stable-fix
+  git push ssh://john.doe@git.example.com:29418/kernel/common HEAD:refs/for/experimental -o t=stable-fix
+----
+
 [[private]]
 ==== Private Changes
 
diff --git a/WORKSPACE b/WORKSPACE
index b915ed10..d782c23 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -417,8 +417,8 @@
 
 maven_jar(
     name = "auto_value",
-    artifact = "com.google.auto.value:auto-value:1.5.3",
-    sha1 = "514df6a7c7938de35c7f68dc8b8f22df86037f38",
+    artifact = "com.google.auto.value:auto-value:1.5.4",
+    sha1 = "65183ddd1e9542d69d8f613fdae91540d04e1476",
 )
 
 # Transitive dependency of commons-compress
@@ -701,18 +701,18 @@
     sha1 = "4785a3c21320980282f9f33d0d1264a69040538f",
 )
 
-TRUTH_VERS = "0.36"
+TRUTH_VERS = "0.39"
 
 maven_jar(
     name = "truth",
     artifact = "com.google.truth:truth:" + TRUTH_VERS,
-    sha1 = "7485219d2c1d341097a19382c02bde07e69ff5d2",
+    sha1 = "bd1bf5706ff34eb7ff80fef8b0c4320f112ef899",
 )
 
 maven_jar(
     name = "truth-java8-extension",
     artifact = "com.google.truth.extensions:truth-java8-extension:" + TRUTH_VERS,
-    sha1 = "dcc60988c8f9a051840766ef192a2ef41e7992f1",
+    sha1 = "1499bc88cda9d674afb30da9813b44bcd4512d0d",
 )
 
 # When bumping the easymock version number, make sure to also move powermock to a compatible version
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountApi.java
index 06ceb49..7f4522f 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountApi.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountApi.java
@@ -27,6 +27,7 @@
 import com.google.gwt.core.client.JsArray;
 import com.google.gwt.core.client.JsArrayString;
 import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwtorm.client.KeyUtil;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -49,7 +50,7 @@
   public static void suggest(String query, int limit, AsyncCallback<JsArray<AccountInfo>> cb) {
     new RestApi("/accounts/")
         .addParameterTrue("suggest")
-        .addParameter("q", query)
+        .addParameterRaw("q", KeyUtil.encode(query))
         .addParameter("n", limit)
         .background()
         .get(cb);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Assignee.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Assignee.java
index 0fd85f1..a376782 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Assignee.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Assignee.java
@@ -102,6 +102,7 @@
     this.changeId = info.legacyId();
     this.project = info.projectNameKey();
     this.canEdit = info.hasActions() && info.actions().containsKey("assignee");
+    assigneeSuggestOracle.setChange(info);
     setAssignee(info.assignee());
     editAssigneeIcon.setVisible(canEdit);
     if (!canEdit) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AssigneeSuggestOracle.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AssigneeSuggestOracle.java
index 964f7ad..c8bbfc3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AssigneeSuggestOracle.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AssigneeSuggestOracle.java
@@ -16,6 +16,7 @@
 
 import com.google.gerrit.client.account.AccountApi;
 import com.google.gerrit.client.info.AccountInfo;
+import com.google.gerrit.client.info.ChangeInfo;
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.client.rpc.Natives;
 import com.google.gerrit.client.ui.AccountSuggestOracle.AccountSuggestion;
@@ -27,10 +28,17 @@
 
 /** REST API based suggestion Oracle for assignee */
 public class AssigneeSuggestOracle extends SuggestAfterTypingNCharsOracle {
+
+  private ChangeInfo change;
+
+  public void setChange(ChangeInfo change) {
+    this.change = change;
+  }
+
   @Override
   protected void _onRequestSuggestions(Request req, Callback cb) {
     AccountApi.suggest(
-        req.getQuery(),
+        getQuery(req),
         req.getLimit(),
         new GerritCallback<JsArray<AccountInfo>>() {
           @Override
@@ -49,4 +57,13 @@
           }
         });
   }
+
+  private String getQuery(Request req) {
+    StringBuilder query = new StringBuilder();
+    query.append(req.getQuery());
+    if (change != null) {
+      query.append(" cansee:").append(change._number());
+    }
+    return query.toString();
+  }
 }
diff --git a/java/com/google/gerrit/acceptance/AbstractDaemonTest.java b/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
index 09ee8f0..54ba802 100644
--- a/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
+++ b/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
@@ -103,6 +103,7 @@
 import com.google.gerrit.server.group.InternalGroup;
 import com.google.gerrit.server.group.SystemGroupBackend;
 import com.google.gerrit.server.group.db.Groups;
+import com.google.gerrit.server.index.account.AccountIndexer;
 import com.google.gerrit.server.index.change.ChangeIndex;
 import com.google.gerrit.server.index.change.ChangeIndexCollection;
 import com.google.gerrit.server.index.change.ChangeIndexer;
@@ -273,6 +274,7 @@
   @Inject private InProcessProtocol inProcessProtocol;
   @Inject private Provider<AnonymousUser> anonymousUser;
   @Inject private SchemaFactory<ReviewDb> reviewDbProvider;
+  @Inject private AccountIndexer accountIndexer;
   @Inject private Groups groups;
   @Inject private GroupIndexer groupIndexer;
 
@@ -353,6 +355,11 @@
     initSsh();
   }
 
+  protected void evictAndReindexAccount(Account.Id accountId) throws IOException {
+    accountCache.evict(accountId);
+    accountIndexer.index(accountId);
+  }
+
   private void reindexAllGroups() throws OrmException, IOException, ConfigInvalidException {
     Iterable<GroupReference> allGroups = groups.getAllGroupReferences(db)::iterator;
     for (GroupReference group : allGroups) {
@@ -416,9 +423,9 @@
     admin = accountCreator.admin();
     user = accountCreator.user();
 
-    // Evict cached user state in case tests modify it.
-    accountCache.evict(admin.getId());
-    accountCache.evict(user.getId());
+    // Evict and reindex accounts in case tests modify them.
+    evictAndReindexAccount(admin.getId());
+    evictAndReindexAccount(user.getId());
 
     adminRestSession = new RestSession(server, admin);
     userRestSession = new RestSession(server, user);
diff --git a/java/com/google/gerrit/acceptance/AbstractNotificationTest.java b/java/com/google/gerrit/acceptance/AbstractNotificationTest.java
index 36f9b82..303a16a 100644
--- a/java/com/google/gerrit/acceptance/AbstractNotificationTest.java
+++ b/java/com/google/gerrit/acceptance/AbstractNotificationTest.java
@@ -322,7 +322,7 @@
     }
 
     private TestAccount evictAndCopy(TestAccount account) throws IOException {
-      accountCache.evict(account.id);
+      evictAndReindexAccount(account.id);
       return account;
     }
 
diff --git a/java/com/google/gerrit/acceptance/LightweightPluginDaemonTest.java b/java/com/google/gerrit/acceptance/LightweightPluginDaemonTest.java
index 7f932c3..62cc8ce 100644
--- a/java/com/google/gerrit/acceptance/LightweightPluginDaemonTest.java
+++ b/java/com/google/gerrit/acceptance/LightweightPluginDaemonTest.java
@@ -30,7 +30,7 @@
 
   @Rule public TemporaryFolder tempDataDir = new TemporaryFolder();
 
-  private TestServerPlugin plugin;
+  protected TestServerPlugin plugin;
 
   @Before
   public void setUp() throws Exception {
diff --git a/java/com/google/gerrit/acceptance/ProjectResetter.java b/java/com/google/gerrit/acceptance/ProjectResetter.java
index 0e4ea19..86718be 100644
--- a/java/com/google/gerrit/acceptance/ProjectResetter.java
+++ b/java/com/google/gerrit/acceptance/ProjectResetter.java
@@ -30,6 +30,7 @@
 import com.google.gerrit.server.config.AllUsersName;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.index.RefState;
+import com.google.gerrit.server.index.account.AccountIndexer;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.project.RefPatternMatcher;
 import com.google.inject.Inject;
@@ -86,6 +87,7 @@
     private final AllUsersName allUsersName;
     @Nullable private final AccountCreator accountCreator;
     @Nullable private final AccountCache accountCache;
+    @Nullable private final AccountIndexer accountIndexer;
     @Nullable private final ProjectCache projectCache;
 
     @Inject
@@ -94,11 +96,13 @@
         AllUsersName allUsersName,
         @Nullable AccountCreator accountCreator,
         @Nullable AccountCache accountCache,
+        @Nullable AccountIndexer accountIndexer,
         @Nullable ProjectCache projectCache) {
       this.repoManager = repoManager;
       this.allUsersName = allUsersName;
       this.accountCreator = accountCreator;
       this.accountCache = accountCache;
+      this.accountIndexer = accountIndexer;
       this.projectCache = projectCache;
     }
 
@@ -108,6 +112,7 @@
           allUsersName,
           accountCreator,
           accountCache,
+          accountIndexer,
           projectCache,
           input.refsByProject);
     }
@@ -134,6 +139,7 @@
   @Inject private AllUsersName allUsersName;
   @Inject @Nullable private AccountCreator accountCreator;
   @Inject @Nullable private AccountCache accountCache;
+  @Inject @Nullable private AccountIndexer accountIndexer;
   @Inject @Nullable private ProjectCache projectCache;
 
   private final Multimap<Project.NameKey, String> refsPatternByProject;
@@ -148,6 +154,7 @@
       AllUsersName allUsersName,
       @Nullable AccountCreator accountCreator,
       @Nullable AccountCache accountCache,
+      @Nullable AccountIndexer accountIndexer,
       @Nullable ProjectCache projectCache,
       Multimap<Project.NameKey, String> refPatternByProject)
       throws IOException {
@@ -155,6 +162,7 @@
     this.allUsersName = allUsersName;
     this.accountCreator = accountCreator;
     this.accountCache = accountCache;
+    this.accountIndexer = accountIndexer;
     this.projectCache = projectCache;
     this.refsPatternByProject = refPatternByProject;
     this.savedRefStatesByProject = readRefStates();
@@ -292,7 +300,7 @@
     if (accountCreator != null) {
       accountCreator.evict(deletedAccounts);
     }
-    if (accountCache != null) {
+    if (accountCache != null || accountIndexer != null) {
       Set<Account.Id> modifiedAccounts =
           new HashSet<>(accountIds(restoredRefsByProject.get(allUsersName)));
 
@@ -304,23 +312,33 @@
           for (Account.Id id :
               accountIds(
                   repo.getAllRefs().values().stream().map(r -> r.getName()).collect(toSet()))) {
-            accountCache.evict(id);
+            evictAndReindexAccount(id);
           }
         }
 
         // Remove deleted accounts from the cache and index.
         for (Account.Id id : deletedAccounts) {
-          accountCache.evict(id);
+          evictAndReindexAccount(id);
         }
       } else {
         // Evict and reindex all modified and deleted accounts.
         for (Account.Id id : Sets.union(modifiedAccounts, deletedAccounts)) {
-          accountCache.evict(id);
+          evictAndReindexAccount(id);
         }
       }
     }
   }
 
+  private void evictAndReindexAccount(Account.Id accountId) throws IOException {
+    if (accountCache != null) {
+      accountCache.evict(accountId);
+    }
+
+    if (accountIndexer != null) {
+      accountIndexer.index(accountId);
+    }
+  }
+
   private Set<Account.Id> accountIds(Collection<String> refs) {
     return refs.stream()
         .filter(r -> r.startsWith(REFS_USERS))
diff --git a/java/com/google/gerrit/elasticsearch/BUILD b/java/com/google/gerrit/elasticsearch/BUILD
index f6d4608..0aa7a39 100644
--- a/java/com/google/gerrit/elasticsearch/BUILD
+++ b/java/com/google/gerrit/elasticsearch/BUILD
@@ -6,6 +6,7 @@
         "//java/com/google/gerrit/extensions:api",
         "//java/com/google/gerrit/index",
         "//java/com/google/gerrit/index:query_exception",
+        "//java/com/google/gerrit/index/project",
         "//java/com/google/gerrit/lifecycle",
         "//java/com/google/gerrit/reviewdb:server",
         "//java/com/google/gerrit/server",
diff --git a/java/com/google/gerrit/elasticsearch/ElasticIndexModule.java b/java/com/google/gerrit/elasticsearch/ElasticIndexModule.java
index 441653a..5a9c6ac 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticIndexModule.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticIndexModule.java
@@ -18,6 +18,7 @@
 
 import com.google.gerrit.index.IndexConfig;
 import com.google.gerrit.index.Schema;
+import com.google.gerrit.index.project.ProjectIndex;
 import com.google.gerrit.lifecycle.LifecycleModule;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.index.IndexModule;
@@ -27,7 +28,6 @@
 import com.google.gerrit.server.index.account.AccountIndex;
 import com.google.gerrit.server.index.change.ChangeIndex;
 import com.google.gerrit.server.index.group.GroupIndex;
-import com.google.gerrit.server.index.project.ProjectIndex;
 import com.google.inject.AbstractModule;
 import com.google.inject.Provides;
 import com.google.inject.Singleton;
diff --git a/java/com/google/gerrit/elasticsearch/ElasticProjectIndex.java b/java/com/google/gerrit/elasticsearch/ElasticProjectIndex.java
index a564e5b..a4046cd 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticProjectIndex.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticProjectIndex.java
@@ -18,6 +18,9 @@
 import com.google.gerrit.elasticsearch.ElasticMapping.MappingProperties;
 import com.google.gerrit.index.QueryOptions;
 import com.google.gerrit.index.Schema;
+import com.google.gerrit.index.project.ProjectData;
+import com.google.gerrit.index.project.ProjectField;
+import com.google.gerrit.index.project.ProjectIndex;
 import com.google.gerrit.index.query.DataSource;
 import com.google.gerrit.index.query.Predicate;
 import com.google.gerrit.index.query.QueryParseException;
@@ -25,10 +28,7 @@
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.gerrit.server.index.IndexUtils;
-import com.google.gerrit.server.index.project.ProjectField;
-import com.google.gerrit.server.index.project.ProjectIndex;
 import com.google.gerrit.server.project.ProjectCache;
-import com.google.gerrit.server.project.ProjectData;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import com.google.inject.Inject;
diff --git a/java/com/google/gerrit/elasticsearch/ElasticQueryBuilder.java b/java/com/google/gerrit/elasticsearch/ElasticQueryBuilder.java
index a470696..6905cf4 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticQueryBuilder.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticQueryBuilder.java
@@ -21,6 +21,7 @@
 import com.google.gerrit.index.query.IntegerRangePredicate;
 import com.google.gerrit.index.query.NotPredicate;
 import com.google.gerrit.index.query.OrPredicate;
+import com.google.gerrit.index.query.PostFilterPredicate;
 import com.google.gerrit.index.query.Predicate;
 import com.google.gerrit.index.query.QueryParseException;
 import com.google.gerrit.index.query.RegexPredicate;
@@ -43,6 +44,8 @@
       return not(p);
     } else if (p instanceof IndexPredicate) {
       return fieldQuery((IndexPredicate<T>) p);
+    } else if (p instanceof PostFilterPredicate) {
+      return QueryBuilders.matchAllQuery();
     } else {
       throw new QueryParseException("cannot create query for index: " + p);
     }
diff --git a/java/com/google/gerrit/extensions/api/changes/RevertInput.java b/java/com/google/gerrit/extensions/api/changes/RevertInput.java
index 893472e..c1be9b0 100644
--- a/java/com/google/gerrit/extensions/api/changes/RevertInput.java
+++ b/java/com/google/gerrit/extensions/api/changes/RevertInput.java
@@ -15,7 +15,13 @@
 package com.google.gerrit.extensions.api.changes;
 
 import com.google.gerrit.extensions.restapi.DefaultInput;
+import java.util.Map;
 
 public class RevertInput {
   @DefaultInput public String message;
+
+  /** Who to send email notifications to after change is created. */
+  public NotifyHandling notify = NotifyHandling.ALL;
+
+  public Map<RecipientType, NotifyInfo> notifyDetails;
 }
diff --git a/java/com/google/gerrit/httpd/gitweb/GitwebServlet.java b/java/com/google/gerrit/httpd/gitweb/GitwebServlet.java
index a498d12..b39f027 100644
--- a/java/com/google/gerrit/httpd/gitweb/GitwebServlet.java
+++ b/java/com/google/gerrit/httpd/gitweb/GitwebServlet.java
@@ -36,6 +36,7 @@
 import com.google.common.base.Splitter;
 import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.extensions.restapi.Url;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.AnonymousUser;
@@ -51,6 +52,7 @@
 import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.gerrit.server.permissions.ProjectPermission;
 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.inject.Inject;
@@ -412,33 +414,45 @@
     }
 
     Project.NameKey nameKey = new Project.NameKey(name);
+    ProjectState projectState;
     try {
-      if (projectCache.checkedGet(nameKey) == null) {
-        notFound(req, rsp);
+      projectState = projectCache.checkedGet(nameKey);
+      if (projectState == null) {
+        sendErrorOrRedirect(req, rsp, HttpServletResponse.SC_NOT_FOUND);
         return;
       }
+
+      projectState.checkStatePermitsRead();
       permissionBackend.user(userProvider).project(nameKey).check(ProjectPermission.READ);
     } catch (AuthException e) {
-      notFound(req, rsp);
+      sendErrorOrRedirect(req, rsp, HttpServletResponse.SC_NOT_FOUND);
       return;
     } catch (IOException | PermissionBackendException err) {
       log.error("cannot load " + name, err);
       rsp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
       return;
+    } catch (ResourceConflictException e) {
+      sendErrorOrRedirect(req, rsp, HttpServletResponse.SC_CONFLICT);
+      return;
     }
 
     try (Repository repo = repoManager.openRepository(nameKey)) {
       CacheHeaders.setNotCacheable(rsp);
-      exec(req, rsp, nameKey);
+      exec(req, rsp, projectState);
     } catch (RepositoryNotFoundException e) {
       getServletContext().log("Cannot open repository", e);
       rsp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
     }
   }
 
-  private void notFound(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
+  /**
+   * Sends error response if the user is authenticated. Or redirect the user to the login page. By
+   * doing this, anonymous users cannot infer the existence of a resource from the status code.
+   */
+  private void sendErrorOrRedirect(HttpServletRequest req, HttpServletResponse rsp, int statusCode)
+      throws IOException {
     if (userProvider.get().isIdentifiedUser()) {
-      rsp.sendError(HttpServletResponse.SC_NOT_FOUND);
+      rsp.sendError(statusCode);
     } else {
       rsp.sendRedirect(getLoginRedirectUrl(req));
     }
@@ -475,13 +489,13 @@
     return params;
   }
 
-  private void exec(HttpServletRequest req, HttpServletResponse rsp, Project.NameKey project)
+  private void exec(HttpServletRequest req, HttpServletResponse rsp, ProjectState projectState)
       throws IOException {
     final Process proc =
         Runtime.getRuntime()
             .exec(
                 new String[] {gitwebCgi.toAbsolutePath().toString()},
-                makeEnv(req, project),
+                makeEnv(req, projectState),
                 gitwebCgi.toAbsolutePath().getParent().toFile());
 
     copyStderrToLog(proc.getErrorStream());
@@ -524,7 +538,7 @@
     }
   }
 
-  private String[] makeEnv(HttpServletRequest req, Project.NameKey nameKey) {
+  private String[] makeEnv(HttpServletRequest req, ProjectState projectState) {
     final EnvList env = new EnvList(_env);
     final int contentLength = Math.max(0, req.getContentLength());
 
@@ -562,15 +576,17 @@
       env.set("HTTP_" + name.toUpperCase().replace('-', '_'), value);
     }
 
+    Project.NameKey nameKey = projectState.getNameKey();
     env.set("GERRIT_CONTEXT_PATH", req.getContextPath() + "/");
     env.set("GERRIT_PROJECT_NAME", nameKey.get());
 
     env.set("GITWEB_PROJECTROOT", repoManager.getBasePath(nameKey).toAbsolutePath().toString());
 
-    if (permissionBackend
-        .user(anonymousUserProvider)
-        .project(nameKey)
-        .testOrFalse(ProjectPermission.READ)) {
+    if (projectState.statePermitsRead()
+        && permissionBackend
+            .user(anonymousUserProvider)
+            .project(nameKey)
+            .testOrFalse(ProjectPermission.READ)) {
       env.set("GERRIT_ANONYMOUS_READ", "1");
     }
 
diff --git a/java/com/google/gerrit/httpd/init/WebAppInitializer.java b/java/com/google/gerrit/httpd/init/WebAppInitializer.java
index d7dca11..bf1dd35 100644
--- a/java/com/google/gerrit/httpd/init/WebAppInitializer.java
+++ b/java/com/google/gerrit/httpd/init/WebAppInitializer.java
@@ -52,6 +52,7 @@
 import com.google.gerrit.server.config.CanonicalWebUrlModule;
 import com.google.gerrit.server.config.DownloadConfig;
 import com.google.gerrit.server.config.GerritGlobalModule;
+import com.google.gerrit.server.config.GerritInstanceNameModule;
 import com.google.gerrit.server.config.GerritOptions;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.GerritServerConfigModule;
@@ -366,6 +367,7 @@
     modules.add(createIndexModule());
 
     modules.add(new WorkQueue.Module());
+    modules.add(new GerritInstanceNameModule());
     modules.add(
         new CanonicalWebUrlModule() {
           @Override
diff --git a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
index d070966..131dbf9 100644
--- a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
+++ b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
@@ -46,6 +46,7 @@
 import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
 import static javax.servlet.http.HttpServletResponse.SC_OK;
 import static javax.servlet.http.HttpServletResponse.SC_PRECONDITION_FAILED;
+import static javax.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE;
 
 import com.google.common.base.CharMatcher;
 import com.google.common.base.Joiner;
@@ -102,9 +103,11 @@
 import com.google.gerrit.server.audit.AuditService;
 import com.google.gerrit.server.audit.ExtendedHttpAuditEvent;
 import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.git.LockFailureException;
 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.update.UpdateException;
 import com.google.gerrit.util.http.RequestUtil;
 import com.google.gson.ExclusionStrategy;
 import com.google.gson.FieldAttributes;
@@ -480,6 +483,15 @@
     } catch (NotImplementedException e) {
       responseBytes =
           replyError(req, res, status = SC_NOT_IMPLEMENTED, messageOr(e, "Not Implemented"), e);
+    } catch (UpdateException e) {
+      Throwable t = e.getCause();
+      if (t instanceof LockFailureException) {
+        responseBytes =
+            replyError(req, res, status = SC_SERVICE_UNAVAILABLE, messageOr(t, "Lock failure"), e);
+      } else {
+        status = SC_INTERNAL_SERVER_ERROR;
+        responseBytes = handleException(e, req, res);
+      }
     } catch (Exception e) {
       status = SC_INTERNAL_SERVER_ERROR;
       responseBytes = handleException(e, req, res);
diff --git a/java/com/google/gerrit/index/project/BUILD b/java/com/google/gerrit/index/project/BUILD
new file mode 100644
index 0000000..f32d8c0
--- /dev/null
+++ b/java/com/google/gerrit/index/project/BUILD
@@ -0,0 +1,12 @@
+java_library(
+    name = "project",
+    srcs = glob(["*.java"]),
+    visibility = ["//visibility:public"],
+    deps = [
+        "//java/com/google/gerrit/index",
+        "//java/com/google/gerrit/index:query_exception",
+        "//java/com/google/gerrit/reviewdb:server",
+        "//lib:guava",
+        "//lib/guice",
+    ],
+)
diff --git a/java/com/google/gerrit/server/index/project/IndexedProjectQuery.java b/java/com/google/gerrit/index/project/IndexedProjectQuery.java
similarity index 92%
rename from java/com/google/gerrit/server/index/project/IndexedProjectQuery.java
rename to java/com/google/gerrit/index/project/IndexedProjectQuery.java
index 41bff05..4409ccb 100644
--- a/java/com/google/gerrit/server/index/project/IndexedProjectQuery.java
+++ b/java/com/google/gerrit/index/project/IndexedProjectQuery.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.index.project;
+package com.google.gerrit.index.project;
 
 import com.google.gerrit.index.Index;
 import com.google.gerrit.index.IndexedQuery;
@@ -21,7 +21,6 @@
 import com.google.gerrit.index.query.Predicate;
 import com.google.gerrit.index.query.QueryParseException;
 import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.server.project.ProjectData;
 
 public class IndexedProjectQuery extends IndexedQuery<Project.NameKey, ProjectData>
     implements DataSource<ProjectData> {
diff --git a/java/com/google/gerrit/server/project/ProjectData.java b/java/com/google/gerrit/index/project/ProjectData.java
similarity index 96%
rename from java/com/google/gerrit/server/project/ProjectData.java
rename to java/com/google/gerrit/index/project/ProjectData.java
index 407529d..9d6b571 100644
--- a/java/com/google/gerrit/server/project/ProjectData.java
+++ b/java/com/google/gerrit/index/project/ProjectData.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.project;
+package com.google.gerrit.index.project;
 
 import com.google.common.collect.ImmutableList;
 import com.google.gerrit.reviewdb.client.Project;
diff --git a/java/com/google/gerrit/server/index/project/ProjectField.java b/java/com/google/gerrit/index/project/ProjectField.java
similarity index 94%
rename from java/com/google/gerrit/server/index/project/ProjectField.java
rename to java/com/google/gerrit/index/project/ProjectField.java
index c4f8e9e..4d39f16 100644
--- a/java/com/google/gerrit/server/index/project/ProjectField.java
+++ b/java/com/google/gerrit/index/project/ProjectField.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.index.project;
+package com.google.gerrit.index.project;
 
 import static com.google.gerrit.index.FieldDef.exact;
 import static com.google.gerrit.index.FieldDef.fullText;
@@ -21,7 +21,6 @@
 import com.google.common.collect.Iterables;
 import com.google.gerrit.index.FieldDef;
 import com.google.gerrit.index.SchemaUtil;
-import com.google.gerrit.server.project.ProjectData;
 
 /** Index schema for projects. */
 public class ProjectField {
diff --git a/java/com/google/gerrit/server/index/project/ProjectIndex.java b/java/com/google/gerrit/index/project/ProjectIndex.java
similarity index 83%
rename from java/com/google/gerrit/server/index/project/ProjectIndex.java
rename to java/com/google/gerrit/index/project/ProjectIndex.java
index 5fbdf04..db7302a 100644
--- a/java/com/google/gerrit/server/index/project/ProjectIndex.java
+++ b/java/com/google/gerrit/index/project/ProjectIndex.java
@@ -12,14 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.index.project;
+package com.google.gerrit.index.project;
 
 import com.google.gerrit.index.Index;
 import com.google.gerrit.index.IndexDefinition;
 import com.google.gerrit.index.query.Predicate;
 import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.server.project.ProjectData;
-import com.google.gerrit.server.query.project.ProjectPredicates;
 
 public interface ProjectIndex extends Index<Project.NameKey, ProjectData> {
 
@@ -28,6 +26,6 @@
 
   @Override
   default Predicate<ProjectData> keyPredicate(Project.NameKey nameKey) {
-    return ProjectPredicates.name(nameKey);
+    return new ProjectPredicate(ProjectField.NAME, nameKey.get());
   }
 }
diff --git a/java/com/google/gerrit/server/index/project/ProjectIndexCollection.java b/java/com/google/gerrit/index/project/ProjectIndexCollection.java
similarity index 90%
rename from java/com/google/gerrit/server/index/project/ProjectIndexCollection.java
rename to java/com/google/gerrit/index/project/ProjectIndexCollection.java
index eeebfa1..281f992 100644
--- a/java/com/google/gerrit/server/index/project/ProjectIndexCollection.java
+++ b/java/com/google/gerrit/index/project/ProjectIndexCollection.java
@@ -12,12 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.index.project;
+package com.google.gerrit.index.project;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.gerrit.index.IndexCollection;
 import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.server.project.ProjectData;
 import com.google.inject.Singleton;
 
 @Singleton
diff --git a/java/com/google/gerrit/server/index/project/ProjectIndexRewriter.java b/java/com/google/gerrit/index/project/ProjectIndexRewriter.java
similarity index 93%
rename from java/com/google/gerrit/server/index/project/ProjectIndexRewriter.java
rename to java/com/google/gerrit/index/project/ProjectIndexRewriter.java
index 41d8820..096bb64 100644
--- a/java/com/google/gerrit/server/index/project/ProjectIndexRewriter.java
+++ b/java/com/google/gerrit/index/project/ProjectIndexRewriter.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.index.project;
+package com.google.gerrit.index.project;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
@@ -20,7 +20,6 @@
 import com.google.gerrit.index.QueryOptions;
 import com.google.gerrit.index.query.Predicate;
 import com.google.gerrit.index.query.QueryParseException;
-import com.google.gerrit.server.project.ProjectData;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
diff --git a/java/com/google/gerrit/server/index/project/ProjectIndexer.java b/java/com/google/gerrit/index/project/ProjectIndexer.java
similarity index 94%
rename from java/com/google/gerrit/server/index/project/ProjectIndexer.java
rename to java/com/google/gerrit/index/project/ProjectIndexer.java
index e8a8183..44dccfe 100644
--- a/java/com/google/gerrit/server/index/project/ProjectIndexer.java
+++ b/java/com/google/gerrit/index/project/ProjectIndexer.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.index.project;
+package com.google.gerrit.index.project;
 
 import com.google.gerrit.reviewdb.client.Project;
 import java.io.IOException;
diff --git a/java/com/google/gerrit/index/project/ProjectPredicate.java b/java/com/google/gerrit/index/project/ProjectPredicate.java
new file mode 100644
index 0000000..4926eef
--- /dev/null
+++ b/java/com/google/gerrit/index/project/ProjectPredicate.java
@@ -0,0 +1,24 @@
+// 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.index.project;
+
+import com.google.gerrit.index.FieldDef;
+import com.google.gerrit.index.query.IndexPredicate;
+
+public class ProjectPredicate extends IndexPredicate<ProjectData> {
+  public ProjectPredicate(FieldDef<ProjectData, ?> def, String value) {
+    super(def, value);
+  }
+}
diff --git a/java/com/google/gerrit/server/index/project/ProjectSchemaDefinitions.java b/java/com/google/gerrit/index/project/ProjectSchemaDefinitions.java
similarity index 92%
rename from java/com/google/gerrit/server/index/project/ProjectSchemaDefinitions.java
rename to java/com/google/gerrit/index/project/ProjectSchemaDefinitions.java
index ccece02..cbea4fe 100644
--- a/java/com/google/gerrit/server/index/project/ProjectSchemaDefinitions.java
+++ b/java/com/google/gerrit/index/project/ProjectSchemaDefinitions.java
@@ -12,13 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.index.project;
+package com.google.gerrit.index.project;
 
 import static com.google.gerrit.index.SchemaUtil.schema;
 
 import com.google.gerrit.index.Schema;
 import com.google.gerrit.index.SchemaDefinitions;
-import com.google.gerrit.server.project.ProjectData;
 
 public class ProjectSchemaDefinitions extends SchemaDefinitions<ProjectData> {
 
diff --git a/java/com/google/gerrit/index/query/PostFilterPredicate.java b/java/com/google/gerrit/index/query/PostFilterPredicate.java
new file mode 100644
index 0000000..3e780bf
--- /dev/null
+++ b/java/com/google/gerrit/index/query/PostFilterPredicate.java
@@ -0,0 +1,21 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.index.query;
+
+/**
+ * Matches all documents in the index, with additional filtering done in the subclass's {@code
+ * match} method.
+ */
+public abstract class PostFilterPredicate<T> extends Predicate<T> implements Matchable<T> {}
diff --git a/java/com/google/gerrit/lucene/BUILD b/java/com/google/gerrit/lucene/BUILD
index 2254905..0c53215 100644
--- a/java/com/google/gerrit/lucene/BUILD
+++ b/java/com/google/gerrit/lucene/BUILD
@@ -29,6 +29,7 @@
         "//java/com/google/gerrit/extensions:api",
         "//java/com/google/gerrit/index",
         "//java/com/google/gerrit/index:query_exception",
+        "//java/com/google/gerrit/index/project",
         "//java/com/google/gerrit/lifecycle",
         "//java/com/google/gerrit/reviewdb:server",
         "//java/com/google/gerrit/server",
diff --git a/java/com/google/gerrit/lucene/LuceneIndexModule.java b/java/com/google/gerrit/lucene/LuceneIndexModule.java
index e44c9c6..5c6cb27 100644
--- a/java/com/google/gerrit/lucene/LuceneIndexModule.java
+++ b/java/com/google/gerrit/lucene/LuceneIndexModule.java
@@ -19,6 +19,7 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.gerrit.index.IndexConfig;
 import com.google.gerrit.index.Schema;
+import com.google.gerrit.index.project.ProjectIndex;
 import com.google.gerrit.lifecycle.LifecycleModule;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.index.IndexModule;
@@ -28,7 +29,6 @@
 import com.google.gerrit.server.index.account.AccountIndex;
 import com.google.gerrit.server.index.change.ChangeIndex;
 import com.google.gerrit.server.index.group.GroupIndex;
-import com.google.gerrit.server.index.project.ProjectIndex;
 import com.google.inject.AbstractModule;
 import com.google.inject.Provides;
 import com.google.inject.Singleton;
diff --git a/java/com/google/gerrit/lucene/LuceneProjectIndex.java b/java/com/google/gerrit/lucene/LuceneProjectIndex.java
index e776a8b..3e2dc1e 100644
--- a/java/com/google/gerrit/lucene/LuceneProjectIndex.java
+++ b/java/com/google/gerrit/lucene/LuceneProjectIndex.java
@@ -14,10 +14,12 @@
 
 package com.google.gerrit.lucene;
 
-import static com.google.gerrit.server.index.project.ProjectField.NAME;
+import static com.google.gerrit.index.project.ProjectField.NAME;
 
 import com.google.gerrit.index.QueryOptions;
 import com.google.gerrit.index.Schema;
+import com.google.gerrit.index.project.ProjectData;
+import com.google.gerrit.index.project.ProjectIndex;
 import com.google.gerrit.index.query.DataSource;
 import com.google.gerrit.index.query.Predicate;
 import com.google.gerrit.index.query.QueryParseException;
@@ -25,9 +27,7 @@
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.gerrit.server.index.IndexUtils;
-import com.google.gerrit.server.index.project.ProjectIndex;
 import com.google.gerrit.server.project.ProjectCache;
-import com.google.gerrit.server.project.ProjectData;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.assistedinject.Assisted;
diff --git a/java/com/google/gerrit/lucene/QueryBuilder.java b/java/com/google/gerrit/lucene/QueryBuilder.java
index 2f2a1cd..4500942 100644
--- a/java/com/google/gerrit/lucene/QueryBuilder.java
+++ b/java/com/google/gerrit/lucene/QueryBuilder.java
@@ -28,6 +28,7 @@
 import com.google.gerrit.index.query.IntegerRangePredicate;
 import com.google.gerrit.index.query.NotPredicate;
 import com.google.gerrit.index.query.OrPredicate;
+import com.google.gerrit.index.query.PostFilterPredicate;
 import com.google.gerrit.index.query.Predicate;
 import com.google.gerrit.index.query.QueryParseException;
 import com.google.gerrit.index.query.RegexPredicate;
@@ -76,6 +77,8 @@
       return not(p);
     } else if (p instanceof IndexPredicate) {
       return fieldQuery((IndexPredicate<V>) p);
+    } else if (p instanceof PostFilterPredicate) {
+      return new MatchAllDocsQuery();
     } else {
       throw new QueryParseException("cannot create query for index: " + p);
     }
diff --git a/java/com/google/gerrit/pgm/Daemon.java b/java/com/google/gerrit/pgm/Daemon.java
index d73a4c7..88b71aa 100644
--- a/java/com/google/gerrit/pgm/Daemon.java
+++ b/java/com/google/gerrit/pgm/Daemon.java
@@ -62,6 +62,7 @@
 import com.google.gerrit.server.config.CanonicalWebUrlProvider;
 import com.google.gerrit.server.config.DownloadConfig;
 import com.google.gerrit.server.config.GerritGlobalModule;
+import com.google.gerrit.server.config.GerritInstanceNameModule;
 import com.google.gerrit.server.config.GerritOptions;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.events.EventBroker;
@@ -433,6 +434,7 @@
     modules.add(new RestCacheAdminModule());
     modules.add(new GpgModule(config));
     modules.add(new StartupChecks.Module());
+    modules.add(new GerritInstanceNameModule());
     if (MoreObjects.firstNonNull(httpd, true)) {
       modules.add(
           new CanonicalWebUrlModule() {
diff --git a/java/com/google/gerrit/pgm/init/InitIndex.java b/java/com/google/gerrit/pgm/init/InitIndex.java
index 6ad0a6b..740f4ce 100644
--- a/java/com/google/gerrit/pgm/init/InitIndex.java
+++ b/java/com/google/gerrit/pgm/init/InitIndex.java
@@ -40,6 +40,7 @@
   private final SitePaths site;
   private final InitFlags initFlags;
   private final Section gerrit;
+  private final Section.Factory sections;
 
   @Inject
   InitIndex(ConsoleUI ui, Section.Factory sections, SitePaths site, InitFlags initFlags) {
@@ -48,6 +49,7 @@
     this.gerrit = sections.get("gerrit", null);
     this.site = site;
     this.initFlags = initFlags;
+    this.sections = sections;
   }
 
   @Override
@@ -59,10 +61,15 @@
     }
 
     if (type == IndexType.ELASTICSEARCH) {
-      index.select("Transport protocol", "protocol", "http", Sets.newHashSet("http", "https"));
-      index.string("Hostname", "hostname", "localhost");
-      index.string("Port", "port", "9200");
-      index.string("Index Name", "name", "gerrit");
+      Section elasticsearch = sections.get("elasticsearch", null);
+      elasticsearch.string("Index Prefix", "prefix", "gerrit");
+      String name = ui.readString("default", "Server Name");
+
+      Section defaultServer = sections.get("elasticsearch", name);
+      defaultServer.select(
+          "Transport protocol", "protocol", "http", Sets.newHashSet("http", "https"));
+      defaultServer.string("Hostname", "hostname", "localhost");
+      defaultServer.string("Port", "port", "9200");
     }
 
     if ((site.isNew || isEmptySite()) && type == IndexType.LUCENE) {
diff --git a/java/com/google/gerrit/reviewdb/server/DisallowReadFromChangesReviewDbWrapper.java b/java/com/google/gerrit/reviewdb/server/DisallowReadFromChangesReviewDbWrapper.java
index d4c6354..fdf3d6c 100644
--- a/java/com/google/gerrit/reviewdb/server/DisallowReadFromChangesReviewDbWrapper.java
+++ b/java/com/google/gerrit/reviewdb/server/DisallowReadFromChangesReviewDbWrapper.java
@@ -41,10 +41,6 @@
     patchComments = new PatchLineComments(delegate.patchComments());
   }
 
-  public ReviewDb unsafeGetDelegate() {
-    return delegate;
-  }
-
   @Override
   public ChangeAccess changes() {
     return changes;
diff --git a/java/com/google/gerrit/reviewdb/server/DisallowReadFromGroupsReviewDbWrapper.java b/java/com/google/gerrit/reviewdb/server/DisallowReadFromGroupsReviewDbWrapper.java
index 640924c..1bfbd37 100644
--- a/java/com/google/gerrit/reviewdb/server/DisallowReadFromGroupsReviewDbWrapper.java
+++ b/java/com/google/gerrit/reviewdb/server/DisallowReadFromGroupsReviewDbWrapper.java
@@ -44,10 +44,6 @@
     byIdAudits = new ByIdAudits(delegate.accountGroupByIdAud());
   }
 
-  public ReviewDb unsafeGetDelegate() {
-    return delegate;
-  }
-
   @Override
   public AccountGroupAccess accountGroups() {
     return groups;
diff --git a/java/com/google/gerrit/reviewdb/server/ReviewDbWrapper.java b/java/com/google/gerrit/reviewdb/server/ReviewDbWrapper.java
index f0a8a34..788c4d4 100644
--- a/java/com/google/gerrit/reviewdb/server/ReviewDbWrapper.java
+++ b/java/com/google/gerrit/reviewdb/server/ReviewDbWrapper.java
@@ -28,6 +28,7 @@
 import com.google.gerrit.reviewdb.client.PatchLineComment;
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gwtorm.jdbc.JdbcSchema;
 import com.google.gwtorm.server.Access;
 import com.google.gwtorm.server.AtomicUpdate;
 import com.google.gwtorm.server.OrmException;
@@ -36,6 +37,13 @@
 import java.util.Map;
 
 public class ReviewDbWrapper implements ReviewDb {
+  public static JdbcSchema unwrapJbdcSchema(ReviewDb db) {
+    if (db instanceof ReviewDbWrapper) {
+      return unwrapJbdcSchema(((ReviewDbWrapper) db).unsafeGetDelegate());
+    }
+    return (JdbcSchema) db;
+  }
+
   protected final ReviewDb delegate;
 
   private boolean inTransaction;
@@ -44,6 +52,10 @@
     this.delegate = checkNotNull(delegate);
   }
 
+  public ReviewDb unsafeGetDelegate() {
+    return delegate;
+  }
+
   public boolean inTransaction() {
     return inTransaction;
   }
diff --git a/java/com/google/gerrit/server/BUILD b/java/com/google/gerrit/server/BUILD
index fb1fc28..94f5062 100644
--- a/java/com/google/gerrit/server/BUILD
+++ b/java/com/google/gerrit/server/BUILD
@@ -34,6 +34,7 @@
         "//java/com/google/gerrit/extensions:api",
         "//java/com/google/gerrit/index",
         "//java/com/google/gerrit/index:query_exception",
+        "//java/com/google/gerrit/index/project",
         "//java/com/google/gerrit/lifecycle",
         "//java/com/google/gerrit/metrics",
         "//java/com/google/gerrit/prettify:server",
diff --git a/java/com/google/gerrit/server/ChangeFinder.java b/java/com/google/gerrit/server/ChangeFinder.java
index cb82778..677b091 100644
--- a/java/com/google/gerrit/server/ChangeFinder.java
+++ b/java/com/google/gerrit/server/ChangeFinder.java
@@ -110,6 +110,14 @@
     this.allowedIdTypes = ImmutableSet.copyOf(configuredChangeIdTypes);
   }
 
+  public ChangeNotes findOne(String id) throws OrmException {
+    List<ChangeNotes> ctls = find(id);
+    if (ctls.size() != 1) {
+      return null;
+    }
+    return ctls.get(0);
+  }
+
   /**
    * Find changes matching the given identifier.
    *
diff --git a/java/com/google/gerrit/server/CommentsUtil.java b/java/com/google/gerrit/server/CommentsUtil.java
index 1c71c70..56b1724 100644
--- a/java/com/google/gerrit/server/CommentsUtil.java
+++ b/java/com/google/gerrit/server/CommentsUtil.java
@@ -491,25 +491,21 @@
   }
 
   public static void setCommentRevId(Comment c, PatchListCache cache, Change change, PatchSet ps)
-      throws OrmException {
+      throws PatchListNotAvailableException {
     checkArgument(
         c.key.patchSetId == ps.getId().get(),
         "cannot set RevId for patch set %s on comment %s",
         ps.getId(),
         c);
     if (c.revId == null) {
-      try {
-        if (Side.fromShort(c.side) == Side.PARENT) {
-          if (c.side < 0) {
-            c.revId = ObjectId.toString(cache.getOldId(change, ps, -c.side));
-          } else {
-            c.revId = ObjectId.toString(cache.getOldId(change, ps, null));
-          }
+      if (Side.fromShort(c.side) == Side.PARENT) {
+        if (c.side < 0) {
+          c.revId = ObjectId.toString(cache.getOldId(change, ps, -c.side));
         } else {
-          c.revId = ps.getRevision().get();
+          c.revId = ObjectId.toString(cache.getOldId(change, ps, null));
         }
-      } catch (PatchListNotAvailableException e) {
-        throw new OrmException(e);
+      } else {
+        c.revId = ps.getRevision().get();
       }
     }
   }
@@ -576,7 +572,11 @@
       // Draft may have been created by a different real user; copy the current real user. (Only
       // applies to X-Gerrit-RunAs, since modifying drafts via on_behalf_of is not allowed.)
       ctx.getUser().updateRealAccountId(d::setRealAuthor);
-      setCommentRevId(d, patchListCache, notes.getChange(), ps);
+      try {
+        setCommentRevId(d, patchListCache, notes.getChange(), ps);
+      } catch (PatchListNotAvailableException e) {
+        throw new OrmException(e);
+      }
     }
     putComments(ctx.getDb(), ctx.getUpdate(psId), PUBLISHED, drafts);
   }
diff --git a/java/com/google/gerrit/server/account/AccountCache.java b/java/com/google/gerrit/server/account/AccountCache.java
index 875bf5f..b6ca1cb 100644
--- a/java/com/google/gerrit/server/account/AccountCache.java
+++ b/java/com/google/gerrit/server/account/AccountCache.java
@@ -16,7 +16,6 @@
 
 import com.google.gerrit.common.Nullable;
 import com.google.gerrit.reviewdb.client.Account;
-import java.io.IOException;
 import java.util.Optional;
 
 /** Caches important (but small) account state to avoid database hits. */
@@ -60,13 +59,12 @@
   Optional<AccountState> getByUsername(String username);
 
   /**
-   * Evicts the account from the cache and triggers a reindex for it.
+   * Evicts the account from the cache.
    *
    * @param accountId account ID of the account that should be evicted
-   * @throws IOException thrown if reindexing fails
    */
-  void evict(@Nullable Account.Id accountId) throws IOException;
+  void evict(@Nullable Account.Id accountId);
 
-  /** Evict all accounts from the cache, but doesn't trigger reindex of all accounts. */
-  void evictAllNoReindex();
+  /** Evict all accounts from the cache. */
+  void evictAll();
 }
diff --git a/java/com/google/gerrit/server/account/AccountCacheImpl.java b/java/com/google/gerrit/server/account/AccountCacheImpl.java
index a8c3436..105a457 100644
--- a/java/com/google/gerrit/server/account/AccountCacheImpl.java
+++ b/java/com/google/gerrit/server/account/AccountCacheImpl.java
@@ -25,10 +25,8 @@
 import com.google.gerrit.server.account.externalids.ExternalIds;
 import com.google.gerrit.server.cache.CacheModule;
 import com.google.gerrit.server.config.AllUsersName;
-import com.google.gerrit.server.index.account.AccountIndexer;
 import com.google.inject.Inject;
 import com.google.inject.Module;
-import com.google.inject.Provider;
 import com.google.inject.Singleton;
 import com.google.inject.TypeLiteral;
 import com.google.inject.name.Named;
@@ -62,18 +60,15 @@
   private final AllUsersName allUsersName;
   private final ExternalIds externalIds;
   private final LoadingCache<Account.Id, Optional<AccountState>> byId;
-  private final Provider<AccountIndexer> indexer;
 
   @Inject
   AccountCacheImpl(
       AllUsersName allUsersName,
       ExternalIds externalIds,
-      @Named(BYID_NAME) LoadingCache<Account.Id, Optional<AccountState>> byId,
-      Provider<AccountIndexer> indexer) {
+      @Named(BYID_NAME) LoadingCache<Account.Id, Optional<AccountState>> byId) {
     this.allUsersName = allUsersName;
     this.externalIds = externalIds;
     this.byId = byId;
-    this.indexer = indexer;
   }
 
   @Override
@@ -111,15 +106,14 @@
   }
 
   @Override
-  public void evict(@Nullable Account.Id accountId) throws IOException {
+  public void evict(@Nullable Account.Id accountId) {
     if (accountId != null) {
       byId.invalidate(accountId);
-      indexer.get().index(accountId);
     }
   }
 
   @Override
-  public void evictAllNoReindex() {
+  public void evictAll() {
     byId.invalidateAll();
   }
 
diff --git a/java/com/google/gerrit/server/account/AccountManager.java b/java/com/google/gerrit/server/account/AccountManager.java
index d86be16..79c57484 100644
--- a/java/com/google/gerrit/server/account/AccountManager.java
+++ b/java/com/google/gerrit/server/account/AccountManager.java
@@ -143,7 +143,21 @@
       try (ReviewDb db = schema.open()) {
         ExternalId id = externalIds.get(who.getExternalIdKey());
         if (id == null) {
+          if (who.getUserName().isPresent()) {
+            ExternalId.Key key = ExternalId.Key.create(SCHEME_USERNAME, who.getUserName().get());
+            ExternalId existingId = externalIds.get(key);
+            if (existingId != null) {
+              // An inconsistency is detected in the database, having a record for scheme "username:"
+              // but no record for scheme "gerrit:". Try to recover by linking
+              // "gerrit:" identity to the existing account.
+              log.warn(
+                  "User {} already has an account; link new identity to the existing account.",
+                  who.getUserName());
+              return link(existingId.accountId(), who);
+            }
+          }
           // New account, automatically create and return.
+          log.info("External ID not found. Attempting to create new account.");
           return create(db, who);
         }
 
@@ -383,6 +397,7 @@
   public AuthResult link(Account.Id to, AuthRequest who)
       throws AccountException, OrmException, IOException, ConfigInvalidException {
     ExternalId extId = externalIds.get(who.getExternalIdKey());
+    log.info("Link another authentication identity to an existing account");
     if (extId != null) {
       if (!extId.accountId().equals(to)) {
         throw new AccountException(
@@ -390,6 +405,7 @@
       }
       update(who, extId);
     } else {
+      log.info("Linking new external ID to the existing account");
       accountsUpdateProvider
           .get()
           .update(
diff --git a/java/com/google/gerrit/server/account/AccountsUpdate.java b/java/com/google/gerrit/server/account/AccountsUpdate.java
index c8244b8..d6e3ce5 100644
--- a/java/com/google/gerrit/server/account/AccountsUpdate.java
+++ b/java/com/google/gerrit/server/account/AccountsUpdate.java
@@ -90,13 +90,23 @@
  * are stored separately in the {@code refs/meta/external-ids} notes branch (see {@link
  * ExternalIdNotes}).
  *
- * <p>On updating an account the account is evicted from the account cache and thus reindexed. The
- * eviction from the account cache is done by the {@link ReindexAfterRefUpdate} class which receives
- * the event about updating the user branch that is triggered by this class. By passing an {@link
- * com.google.gerrit.server.account.externalids.ExternalIdNotes.FactoryNoReindex} factory as
- * parameter of {@link AccountsUpdate.Factory#create(IdentifiedUser, ExternalIdNotesLoader)},
- * reindexing and flushing the account from the account cache can be disabled. If external IDs are
- * updated, the ExternalIdCache is automatically updated.
+ * <p>On updating an account the account is evicted from the account cache and reindexed. The
+ * eviction from the account cache and the reindexing is done by the {@link ReindexAfterRefUpdate}
+ * class which receives the event about updating the user branch that is triggered by this class.
+ *
+ * <p>If external IDs are updated, the ExternalIdCache is automatically updated by {@link
+ * ExternalIdNotes}. In addition {@link ExternalIdNotes} takes care about evicting and reindexing
+ * corresponding accounts. This is needed because external ID updates don't touch the user branches.
+ * Hence in this case the accounts are not evicted and reindexed via {@link ReindexAfterRefUpdate}.
+ *
+ * <p>Reindexing and flushing accounts from the account cache can be disabled by
+ *
+ * <ul>
+ *   <li>binding {@link GitReferenceUpdated#DISABLED} and
+ *   <li>passing an {@link
+ *       com.google.gerrit.server.account.externalids.ExternalIdNotes.FactoryNoReindex} factory as
+ *       parameter of {@link AccountsUpdate.Factory#create(IdentifiedUser, ExternalIdNotesLoader)}
+ * </ul>
  *
  * <p>If there are concurrent account updates updating the user branch in NoteDb may fail with
  * {@link LockFailureException}. In this case the account update is automatically retried and the
diff --git a/java/com/google/gerrit/server/account/GroupControl.java b/java/com/google/gerrit/server/account/GroupControl.java
index 4b223bf..5649629 100644
--- a/java/com/google/gerrit/server/account/GroupControl.java
+++ b/java/com/google/gerrit/server/account/GroupControl.java
@@ -177,6 +177,6 @@
     if (group instanceof GroupDescription.Internal) {
       return ((GroupDescription.Internal) group).isVisibleToAll() || isOwner();
     }
-    return false;
+    return canAdministrateServer();
   }
 }
diff --git a/java/com/google/gerrit/server/account/externalids/ExternalIdNotes.java b/java/com/google/gerrit/server/account/externalids/ExternalIdNotes.java
index 29f69ba..972dfbd 100644
--- a/java/com/google/gerrit/server/account/externalids/ExternalIdNotes.java
+++ b/java/com/google/gerrit/server/account/externalids/ExternalIdNotes.java
@@ -31,7 +31,9 @@
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.git.MetaDataUpdate;
 import com.google.gerrit.server.git.VersionedMetaData;
+import com.google.gerrit.server.index.account.AccountIndexer;
 import com.google.inject.Inject;
+import com.google.inject.Provider;
 import com.google.inject.Singleton;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -109,23 +111,30 @@
   public static class Factory implements ExternalIdNotesLoader {
     private final ExternalIdCache externalIdCache;
     private final AccountCache accountCache;
+    private final Provider<AccountIndexer> accountIndexer;
 
     @Inject
-    Factory(ExternalIdCache externalIdCache, AccountCache accountCache) {
+    Factory(
+        ExternalIdCache externalIdCache,
+        AccountCache accountCache,
+        Provider<AccountIndexer> accountIndexer) {
       this.externalIdCache = externalIdCache;
       this.accountCache = accountCache;
+      this.accountIndexer = accountIndexer;
     }
 
     @Override
     public ExternalIdNotes load(Repository allUsersRepo)
         throws IOException, ConfigInvalidException {
-      return new ExternalIdNotes(externalIdCache, accountCache, allUsersRepo).load();
+      return new ExternalIdNotes(externalIdCache, accountCache, accountIndexer, allUsersRepo)
+          .load();
     }
 
     @Override
     public ExternalIdNotes load(Repository allUsersRepo, @Nullable ObjectId rev)
         throws IOException, ConfigInvalidException {
-      return new ExternalIdNotes(externalIdCache, accountCache, allUsersRepo).load(rev);
+      return new ExternalIdNotes(externalIdCache, accountCache, accountIndexer, allUsersRepo)
+          .load(rev);
     }
   }
 
@@ -141,13 +150,13 @@
     @Override
     public ExternalIdNotes load(Repository allUsersRepo)
         throws IOException, ConfigInvalidException {
-      return new ExternalIdNotes(externalIdCache, null, allUsersRepo).load();
+      return new ExternalIdNotes(externalIdCache, null, null, allUsersRepo).load();
     }
 
     @Override
     public ExternalIdNotes load(Repository allUsersRepo, @Nullable ObjectId rev)
         throws IOException, ConfigInvalidException {
-      return new ExternalIdNotes(externalIdCache, null, allUsersRepo).load(rev);
+      return new ExternalIdNotes(externalIdCache, null, null, allUsersRepo).load(rev);
     }
   }
 
@@ -159,7 +168,7 @@
    */
   public static ExternalIdNotes loadReadOnly(Repository allUsersRepo)
       throws IOException, ConfigInvalidException {
-    return new ExternalIdNotes(new DisabledExternalIdCache(), null, allUsersRepo)
+    return new ExternalIdNotes(new DisabledExternalIdCache(), null, null, allUsersRepo)
         .setReadOnly()
         .load();
   }
@@ -176,7 +185,7 @@
    */
   public static ExternalIdNotes loadReadOnly(Repository allUsersRepo, @Nullable ObjectId rev)
       throws IOException, ConfigInvalidException {
-    return new ExternalIdNotes(new DisabledExternalIdCache(), null, allUsersRepo)
+    return new ExternalIdNotes(new DisabledExternalIdCache(), null, null, allUsersRepo)
         .setReadOnly()
         .load(rev);
   }
@@ -189,11 +198,12 @@
    */
   public static ExternalIdNotes loadNoCacheUpdate(Repository allUsersRepo)
       throws IOException, ConfigInvalidException {
-    return new ExternalIdNotes(new DisabledExternalIdCache(), null, allUsersRepo).load();
+    return new ExternalIdNotes(new DisabledExternalIdCache(), null, null, allUsersRepo).load();
   }
 
   private final ExternalIdCache externalIdCache;
   @Nullable private final AccountCache accountCache;
+  @Nullable private final Provider<AccountIndexer> accountIndexer;
   private final Repository repo;
 
   private NoteMap noteMap;
@@ -211,9 +221,11 @@
   private ExternalIdNotes(
       ExternalIdCache externalIdCache,
       @Nullable AccountCache accountCache,
+      @Nullable Provider<AccountIndexer> accountIndexer,
       Repository allUsersRepo) {
     this.externalIdCache = checkNotNull(externalIdCache, "externalIdCache");
     this.accountCache = accountCache;
+    this.accountIndexer = accountIndexer;
     this.repo = checkNotNull(allUsersRepo, "allUsersRepo");
   }
 
@@ -598,7 +610,8 @@
    *
    * <p>No-op if this instance was created by {@link #loadNoCacheUpdate(Repository)}.
    *
-   * <p>No eviction from account cache if this instance was created by {@link FactoryNoReindex}.
+   * <p>No eviction from account cache and no reindex if this instance was created by {@link
+   * FactoryNoReindex}.
    */
   public void updateCaches() throws IOException {
     checkState(oldRev != null, "no changes committed yet");
@@ -614,14 +627,19 @@
         externalIdCacheUpdates.getRemoved(),
         externalIdCacheUpdates.getAdded());
 
-    if (accountCache != null) {
+    if (accountCache != null || accountIndexer != null) {
       for (Account.Id id :
           Streams.concat(
                   externalIdCacheUpdates.getAdded().stream(),
                   externalIdCacheUpdates.getRemoved().stream())
               .map(ExternalId::accountId)
               .collect(toSet())) {
-        accountCache.evict(id);
+        if (accountCache != null) {
+          accountCache.evict(id);
+        }
+        if (accountIndexer != null) {
+          accountIndexer.get().index(id);
+        }
       }
     }
 
diff --git a/java/com/google/gerrit/server/change/ChangeKindCacheImpl.java b/java/com/google/gerrit/server/change/ChangeKindCacheImpl.java
index a97aa9c..7b44d8f 100644
--- a/java/com/google/gerrit/server/change/ChangeKindCacheImpl.java
+++ b/java/com/google/gerrit/server/change/ChangeKindCacheImpl.java
@@ -16,8 +16,8 @@
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
-import static org.eclipse.jgit.lib.ObjectIdSerializer.read;
-import static org.eclipse.jgit.lib.ObjectIdSerializer.write;
+import static org.eclipse.jgit.lib.ObjectIdSerializer.readWithoutMarker;
+import static org.eclipse.jgit.lib.ObjectIdSerializer.writeWithoutMarker;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.cache.Cache;
@@ -172,14 +172,14 @@
     }
 
     private void writeObject(ObjectOutputStream out) throws IOException {
-      write(out, prior);
-      write(out, next);
+      writeWithoutMarker(out, prior);
+      writeWithoutMarker(out, next);
       out.writeUTF(strategyName);
     }
 
     private void readObject(ObjectInputStream in) throws IOException {
-      prior = read(in);
-      next = read(in);
+      prior = readWithoutMarker(in);
+      next = readWithoutMarker(in);
       strategyName = in.readUTF();
     }
   }
@@ -241,8 +241,15 @@
           return ChangeKind.NO_CHANGE;
         }
 
-        if ((prior.getParentCount() != 1 || next.getParentCount() != 1)
-            && (!onlyFirstParentChanged(prior, next) || prior.getParentCount() == 0)) {
+        if (prior.getParentCount() == 0 || next.getParentCount() == 0) {
+          // At this point we have considered all the kinds that could be applicable to root
+          // commits; the remainder of the checks in this method all assume that both commits have
+          // at least one parent.
+          return ChangeKind.REWORK;
+        }
+
+        if ((prior.getParentCount() > 1 || next.getParentCount() > 1)
+            && !onlyFirstParentChanged(prior, next)) {
           // Trivial rebases done by machine only work well on 1 parent.
           return ChangeKind.REWORK;
         }
diff --git a/java/com/google/gerrit/server/change/MergeabilityCacheImpl.java b/java/com/google/gerrit/server/change/MergeabilityCacheImpl.java
index 2afdb8f..4c80eab 100644
--- a/java/com/google/gerrit/server/change/MergeabilityCacheImpl.java
+++ b/java/com/google/gerrit/server/change/MergeabilityCacheImpl.java
@@ -19,8 +19,8 @@
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.gerrit.server.ioutil.BasicSerialization.readString;
 import static com.google.gerrit.server.ioutil.BasicSerialization.writeString;
-import static org.eclipse.jgit.lib.ObjectIdSerializer.read;
-import static org.eclipse.jgit.lib.ObjectIdSerializer.write;
+import static org.eclipse.jgit.lib.ObjectIdSerializer.readWithoutMarker;
+import static org.eclipse.jgit.lib.ObjectIdSerializer.writeWithoutMarker;
 
 import com.google.common.base.MoreObjects;
 import com.google.common.cache.Cache;
@@ -155,8 +155,8 @@
     }
 
     private void writeObject(ObjectOutputStream out) throws IOException {
-      write(out, commit);
-      write(out, into);
+      writeWithoutMarker(out, commit);
+      writeWithoutMarker(out, into);
       Character c = SUBMIT_TYPES.get(submitType);
       if (c == null) {
         throw new IOException("Invalid submit type: " + submitType);
@@ -166,8 +166,8 @@
     }
 
     private void readObject(ObjectInputStream in) throws IOException {
-      commit = read(in);
-      into = read(in);
+      commit = readWithoutMarker(in);
+      into = readWithoutMarker(in);
       char t = in.readChar();
       submitType = SUBMIT_TYPES.inverse().get(t);
       if (submitType == null) {
diff --git a/java/com/google/gerrit/server/config/GerritInstanceName.java b/java/com/google/gerrit/server/config/GerritInstanceName.java
new file mode 100644
index 0000000..451e8738
--- /dev/null
+++ b/java/com/google/gerrit/server/config/GerritInstanceName.java
@@ -0,0 +1,30 @@
+// 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.server.config;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.google.inject.BindingAnnotation;
+import java.lang.annotation.Retention;
+
+/**
+ * Marker on a {@link String} holding the instance name for this server.
+ *
+ * <p>Note that the String may be null, if the administrator has not configured the value. Clients
+ * must handle such cases explicitly.
+ */
+@Retention(RUNTIME)
+@BindingAnnotation
+public @interface GerritInstanceName {}
diff --git a/java/com/google/gerrit/server/config/GerritInstanceNameModule.java b/java/com/google/gerrit/server/config/GerritInstanceNameModule.java
new file mode 100644
index 0000000..84fc28a
--- /dev/null
+++ b/java/com/google/gerrit/server/config/GerritInstanceNameModule.java
@@ -0,0 +1,27 @@
+// 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.server.config;
+
+import com.google.inject.AbstractModule;
+
+/** Supports binding the {@link GerritInstanceName} annotation. */
+public class GerritInstanceNameModule extends AbstractModule {
+  @Override
+  protected void configure() {
+    bind(String.class)
+        .annotatedWith(GerritInstanceName.class)
+        .toProvider(GerritInstanceNameProvider.class);
+  }
+}
diff --git a/java/com/google/gerrit/server/config/GerritInstanceNameProvider.java b/java/com/google/gerrit/server/config/GerritInstanceNameProvider.java
new file mode 100644
index 0000000..a27b0b3
--- /dev/null
+++ b/java/com/google/gerrit/server/config/GerritInstanceNameProvider.java
@@ -0,0 +1,48 @@
+// 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.server.config;
+
+import com.google.gerrit.common.Nullable;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+import org.eclipse.jgit.lib.Config;
+
+/** Provides {@link GerritInstanceName} from {@code gerrit.name}. */
+@Singleton
+public class GerritInstanceNameProvider implements Provider<String> {
+  private final String instanceName;
+
+  @Inject
+  public GerritInstanceNameProvider(
+      @GerritServerConfig Config config,
+      @CanonicalWebUrl @Nullable Provider<String> canonicalUrlProvider) {
+    this.instanceName = getInstanceName(config, canonicalUrlProvider);
+  }
+
+  private String getInstanceName(Config config, @Nullable Provider<String> canonicalUrlProvider) {
+    String instanceName = config.getString("gerrit", null, "instanceName");
+    if (instanceName != null || canonicalUrlProvider == null) {
+      return instanceName;
+    }
+
+    return canonicalUrlProvider.get();
+  }
+
+  @Override
+  public String get() {
+    return instanceName;
+  }
+}
diff --git a/java/com/google/gerrit/server/config/PluginConfigFactory.java b/java/com/google/gerrit/server/config/PluginConfigFactory.java
index 6310c08..a46efb8 100644
--- a/java/com/google/gerrit/server/config/PluginConfigFactory.java
+++ b/java/com/google/gerrit/server/config/PluginConfigFactory.java
@@ -15,11 +15,11 @@
 package com.google.gerrit.server.config;
 
 import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.server.git.ProjectLevelConfig;
 import com.google.gerrit.server.plugins.Plugin;
 import com.google.gerrit.server.plugins.ReloadPluginListener;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.ProjectCache;
+import com.google.gerrit.server.project.ProjectLevelConfig;
 import com.google.gerrit.server.project.ProjectState;
 import com.google.gerrit.server.securestore.SecureStore;
 import com.google.inject.Inject;
@@ -288,7 +288,7 @@
    */
   public Config getProjectPluginConfigWithInheritance(
       Project.NameKey projectName, String pluginName) throws NoSuchProjectException {
-    return getPluginConfig(projectName, pluginName).getWithInheritance();
+    return getPluginConfig(projectName, pluginName).getWithInheritance(false);
   }
 
   /**
@@ -310,7 +310,55 @@
    */
   public Config getProjectPluginConfigWithInheritance(
       ProjectState projectState, String pluginName) {
-    return projectState.getConfig(pluginName + EXTENSION).getWithInheritance();
+    return projectState.getConfig(pluginName + EXTENSION).getWithInheritance(false);
+  }
+
+  /**
+   * Returns the configuration for the specified plugin that is stored in the '{@code
+   * <plugin-name>.config}' file in the 'refs/meta/config' branch of the specified project.
+   * Parameters from the '{@code <plugin-name>.config}' of the parent project are appended to this
+   * project's '{@code <plugin-name>.config}' files.
+   *
+   * <p>E.g.: child project: [mySection "mySubsection"] myKey = childValue
+   *
+   * <p>parent project: [mySection "mySubsection"] myKey = parentValue anotherKey = someValue
+   *
+   * <p>return: [mySection "mySubsection"] myKey = childValue myKey = parentValue anotherKey =
+   * someValue
+   *
+   * @param projectName the name of the project for which the plugin configuration should be
+   *     returned
+   * @param pluginName the name of the plugin for which the configuration should be returned
+   * @return the plugin configuration from the '{@code <plugin-name>.config}' file of the specified
+   *     project with parameters from the parent projects appended to the project values
+   * @throws NoSuchProjectException thrown if the specified project does not exist
+   */
+  public Config getProjectPluginConfigWithMergedInheritance(
+      Project.NameKey projectName, String pluginName) throws NoSuchProjectException {
+    return getPluginConfig(projectName, pluginName).getWithInheritance(true);
+  }
+
+  /**
+   * Returns the configuration for the specified plugin that is stored in the '{@code
+   * <plugin-name>.config}' file in the 'refs/meta/config' branch of the specified project.
+   * Parameters from the '{@code <plugin-name>.config}' of the parent project are appended to this
+   * project's '{@code <plugin-name>.config}' files.
+   *
+   * <p>E.g.: child project: [mySection "mySubsection"] myKey = childValue
+   *
+   * <p>parent project: [mySection "mySubsection"] myKey = parentValue anotherKey = someValue
+   *
+   * <p>return: [mySection "mySubsection"] myKey = childValue myKey = parentValue anotherKey =
+   * someValue
+   *
+   * @param projectState the project for which the plugin configuration should be returned
+   * @param pluginName the name of the plugin for which the configuration should be returned
+   * @return the plugin configuration from the '{@code <plugin-name>.config}' file of the specified
+   *     project with inheriting non-set parameters from the parent projects
+   */
+  public Config getProjectPluginConfigWithMergedInheritance(
+      ProjectState projectState, String pluginName) {
+    return projectState.getConfig(pluginName + EXTENSION).getWithInheritance(true);
   }
 
   private ProjectLevelConfig getPluginConfig(Project.NameKey projectName, String pluginName)
diff --git a/java/com/google/gerrit/server/git/SubmoduleOp.java b/java/com/google/gerrit/server/git/SubmoduleOp.java
index 56ed432..d7af141 100644
--- a/java/com/google/gerrit/server/git/SubmoduleOp.java
+++ b/java/com/google/gerrit/server/git/SubmoduleOp.java
@@ -14,6 +14,8 @@
 
 package com.google.gerrit.server.git;
 
+import static java.util.Comparator.comparing;
+
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.MultimapBuilder;
 import com.google.common.collect.SetMultimap;
@@ -29,7 +31,6 @@
 import com.google.gerrit.server.git.MergeOpRepoManager.OpenRepo;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.ProjectCache;
-import com.google.gerrit.server.project.ProjectState;
 import com.google.gerrit.server.update.BatchUpdate;
 import com.google.gerrit.server.update.BatchUpdateListener;
 import com.google.gerrit.server.update.RepoContext;
@@ -47,6 +48,7 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
@@ -95,7 +97,6 @@
     private final PersonIdent myIdent;
     private final Config cfg;
     private final ProjectCache projectCache;
-    private final ProjectState.Factory projectStateFactory;
     private final BatchUpdate.Factory batchUpdateFactory;
 
     @Inject
@@ -104,27 +105,18 @@
         @GerritPersonIdent PersonIdent myIdent,
         @GerritServerConfig Config cfg,
         ProjectCache projectCache,
-        ProjectState.Factory projectStateFactory,
         BatchUpdate.Factory batchUpdateFactory) {
       this.gitmodulesFactory = gitmodulesFactory;
       this.myIdent = myIdent;
       this.cfg = cfg;
       this.projectCache = projectCache;
-      this.projectStateFactory = projectStateFactory;
       this.batchUpdateFactory = batchUpdateFactory;
     }
 
     public SubmoduleOp create(Set<Branch.NameKey> updatedBranches, MergeOpRepoManager orm)
         throws SubmoduleException {
       return new SubmoduleOp(
-          gitmodulesFactory,
-          myIdent,
-          cfg,
-          projectCache,
-          projectStateFactory,
-          batchUpdateFactory,
-          updatedBranches,
-          orm);
+          gitmodulesFactory, myIdent, cfg, projectCache, batchUpdateFactory, updatedBranches, orm);
     }
   }
 
@@ -133,7 +125,6 @@
   private final GitModules.Factory gitmodulesFactory;
   private final PersonIdent myIdent;
   private final ProjectCache projectCache;
-  private final ProjectState.Factory projectStateFactory;
   private final BatchUpdate.Factory batchUpdateFactory;
   private final VerboseSuperprojectUpdate verboseSuperProject;
   private final boolean enableSuperProjectSubscriptions;
@@ -160,7 +151,6 @@
       PersonIdent myIdent,
       Config cfg,
       ProjectCache projectCache,
-      ProjectState.Factory projectStateFactory,
       BatchUpdate.Factory batchUpdateFactory,
       Set<Branch.NameKey> updatedBranches,
       MergeOpRepoManager orm)
@@ -168,7 +158,6 @@
     this.gitmodulesFactory = gitmodulesFactory;
     this.myIdent = myIdent;
     this.projectCache = projectCache;
-    this.projectStateFactory = projectStateFactory;
     this.batchUpdateFactory = batchUpdateFactory;
     this.verboseSuperProject =
         cfg.getEnum("submodule", null, "verboseSuperprojectUpdate", VerboseSuperprojectUpdate.TRUE);
@@ -332,8 +321,7 @@
     logDebug("Calculating possible superprojects for " + srcBranch);
     Collection<SubmoduleSubscription> ret = new ArrayList<>();
     Project.NameKey srcProject = srcBranch.getParentKey();
-    ProjectConfig cfg = projectCache.get(srcProject).getConfig();
-    for (SubscribeSection s : projectStateFactory.create(cfg).getSubscribeSections(srcBranch)) {
+    for (SubscribeSection s : projectCache.get(srcProject).getSubscribeSections(srcBranch)) {
       logDebug("Checking subscribe section " + s);
       Collection<Branch.NameKey> branches = getDestinationBranches(srcBranch, s);
       for (Branch.NameKey targetBranch : branches) {
@@ -416,7 +404,10 @@
     DirCache dc = readTree(or.rw, currentCommit);
     DirCacheEditor ed = dc.editor();
     int count = 0;
-    for (SubmoduleSubscription s : targets.get(subscriber)) {
+
+    List<SubmoduleSubscription> subscriptions = new ArrayList<>(targets.get(subscriber));
+    Collections.sort(subscriptions, comparing((SubmoduleSubscription s) -> s.getPath()));
+    for (SubmoduleSubscription s : subscriptions) {
       if (count > 0) {
         msgbuf.append("\n\n");
       }
diff --git a/java/com/google/gerrit/server/git/TagSet.java b/java/com/google/gerrit/server/git/TagSet.java
index 95bf947..118223b 100644
--- a/java/com/google/gerrit/server/git/TagSet.java
+++ b/java/com/google/gerrit/server/git/TagSet.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.server.git;
 
-import static org.eclipse.jgit.lib.ObjectIdSerializer.read;
-import static org.eclipse.jgit.lib.ObjectIdSerializer.write;
+import static org.eclipse.jgit.lib.ObjectIdSerializer.readWithoutMarker;
+import static org.eclipse.jgit.lib.ObjectIdSerializer.writeWithoutMarker;
 
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.client.Project;
@@ -194,13 +194,13 @@
     for (int i = 0; i < refCnt; i++) {
       String name = in.readUTF();
       int flag = in.readInt();
-      ObjectId id = read(in);
+      ObjectId id = readWithoutMarker(in);
       refs.put(name, new CachedRef(flag, id));
     }
 
     int tagCnt = in.readInt();
     for (int i = 0; i < tagCnt; i++) {
-      ObjectId id = read(in);
+      ObjectId id = readWithoutMarker(in);
       BitSet flags = (BitSet) in.readObject();
       tags.add(new Tag(id, flags));
     }
@@ -211,12 +211,12 @@
     for (Map.Entry<String, CachedRef> e : refs.entrySet()) {
       out.writeUTF(e.getKey());
       out.writeInt(e.getValue().flag);
-      write(out, e.getValue().get());
+      writeWithoutMarker(out, e.getValue().get());
     }
 
     out.writeInt(tags.size());
     for (Tag tag : tags) {
-      write(out, tag);
+      writeWithoutMarker(out, tag);
       out.writeObject(tag.refFlags);
     }
   }
diff --git a/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java b/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java
index 597bce1..bd45bc2 100644
--- a/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java
@@ -18,6 +18,7 @@
 import com.google.gerrit.common.Nullable;
 import com.google.gerrit.common.data.Capable;
 import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.IdentifiedUser;
@@ -228,8 +229,9 @@
     // Check objects mentioned inside the incoming pack file are reachable from visible refs.
     this.perm = permissionBackend.user(user).project(projectName);
     try {
+      projectState.checkStatePermitsRead();
       this.perm.check(ProjectPermission.READ);
-    } catch (AuthException e) {
+    } catch (AuthException | ResourceConflictException e) {
       rp.setCheckReferencedObjectsAreReachable(receiveConfig.checkReferencedObjectsAreReachable);
     }
 
diff --git a/java/com/google/gerrit/server/group/db/AuditLogReader.java b/java/com/google/gerrit/server/group/db/AuditLogReader.java
index 64b464d..967b0d2 100644
--- a/java/com/google/gerrit/server/group/db/AuditLogReader.java
+++ b/java/com/google/gerrit/server/group/db/AuditLogReader.java
@@ -46,13 +46,13 @@
 
 /** NoteDb reader for group audit log. */
 @Singleton
-class AuditLogReader {
+public class AuditLogReader {
   private static final Logger log = LoggerFactory.getLogger(AuditLogReader.class);
 
   private final String serverId;
 
   @Inject
-  AuditLogReader(@GerritServerId String serverId) {
+  public AuditLogReader(@GerritServerId String serverId) {
     this.serverId = serverId;
   }
 
@@ -60,8 +60,8 @@
   // ReviewDb. Once ReviewDb is gone, the audit record interface becomes more flexible and we can
   // revisit this, e.g. to do only a single walk, or even change the record types.
 
-  ImmutableList<AccountGroupMemberAudit> getMembersAudit(Repository repo, AccountGroup.UUID uuid)
-      throws IOException, ConfigInvalidException {
+  public ImmutableList<AccountGroupMemberAudit> getMembersAudit(
+      Repository repo, AccountGroup.UUID uuid) throws IOException, ConfigInvalidException {
     return getMembersAudit(getGroupId(repo, uuid), parseCommits(repo, uuid));
   }
 
@@ -97,8 +97,8 @@
     return result.build();
   }
 
-  ImmutableList<AccountGroupByIdAud> getSubgroupsAudit(Repository repo, AccountGroup.UUID uuid)
-      throws IOException, ConfigInvalidException {
+  public ImmutableList<AccountGroupByIdAud> getSubgroupsAudit(
+      Repository repo, AccountGroup.UUID uuid) throws IOException, ConfigInvalidException {
     return getSubgroupsAudit(getGroupId(repo, uuid), parseCommits(repo, uuid));
   }
 
diff --git a/java/com/google/gerrit/server/group/db/GroupConfig.java b/java/com/google/gerrit/server/group/db/GroupConfig.java
index 0d86674..4ab934e 100644
--- a/java/com/google/gerrit/server/group/db/GroupConfig.java
+++ b/java/com/google/gerrit/server/group/db/GroupConfig.java
@@ -228,7 +228,7 @@
    * which don't always necessarily have a name. Nowadays, we enforce that groups always have names.
    * When we remove the migration code, we can probably remove this method as well.
    */
-  void setAllowSaveEmptyName() {
+  public void setAllowSaveEmptyName() {
     this.allowSaveEmptyName = true;
   }
 
@@ -243,7 +243,7 @@
   }
 
   @Override
-  protected String getRefName() {
+  public String getRefName() {
     return ref;
   }
 
diff --git a/java/com/google/gerrit/server/group/db/GroupsUpdate.java b/java/com/google/gerrit/server/group/db/GroupsUpdate.java
index a3aae83..f10409e 100644
--- a/java/com/google/gerrit/server/group/db/GroupsUpdate.java
+++ b/java/com/google/gerrit/server/group/db/GroupsUpdate.java
@@ -43,7 +43,6 @@
 import com.google.gerrit.server.account.GroupIncludeCache;
 import com.google.gerrit.server.audit.AuditService;
 import com.google.gerrit.server.config.AllUsersName;
-import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.GerritServerId;
 import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
 import com.google.gerrit.server.git.GitRepositoryManager;
@@ -69,7 +68,6 @@
 import java.util.concurrent.TimeUnit;
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.BatchRefUpdate;
-import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.PersonIdent;
 import org.eclipse.jgit.lib.Repository;
@@ -114,7 +112,6 @@
   private final GroupsMigration groupsMigration;
   private final GitReferenceUpdated gitRefUpdated;
   private final RetryHelper retryHelper;
-  private final boolean reviewDbUpdatesAreBlocked;
 
   @Inject
   GroupsUpdate(
@@ -131,7 +128,6 @@
       @GerritPersonIdent PersonIdent serverIdent,
       MetaDataUpdate.InternalFactory metaDataUpdateInternalFactory,
       GroupsMigration groupsMigration,
-      @GerritServerConfig Config config,
       GitReferenceUpdated gitRefUpdated,
       RetryHelper retryHelper,
       @Assisted @Nullable IdentifiedUser currentUser) {
@@ -152,7 +148,6 @@
         getMetaDataUpdateFactory(
             metaDataUpdateInternalFactory, currentUser, serverIdent, auditLogFormatter);
     authorIdent = getAuthorIdent(serverIdent, currentUser);
-    reviewDbUpdatesAreBlocked = config.getBoolean("user", null, "blockReviewDbGroupUpdates", false);
   }
 
   private static MetaDataUpdateFactory getMetaDataUpdateFactory(
@@ -276,7 +271,6 @@
   private InternalGroup createGroupInReviewDb(
       ReviewDb db, InternalGroupCreation groupCreation, InternalGroupUpdate groupUpdate)
       throws OrmException {
-    checkIfReviewDbUpdatesAreBlocked();
 
     AccountGroupName gn = new AccountGroupName(groupCreation.getNameKey(), groupCreation.getId());
     // first insert the group name to validate that the group name hasn't
@@ -316,8 +310,6 @@
 
   private UpdateResult updateGroupInReviewDb(
       ReviewDb db, AccountGroup group, InternalGroupUpdate groupUpdate) throws OrmException {
-    checkIfReviewDbUpdatesAreBlocked();
-
     AccountGroup.NameKey originalName = group.getNameKey();
     applyUpdate(group, groupUpdate);
     AccountGroup.NameKey updatedName = group.getNameKey();
@@ -637,12 +629,6 @@
     result.getDeletedSubgroups().forEach(groupIncludeCache::evictParentGroupsOf);
   }
 
-  private void checkIfReviewDbUpdatesAreBlocked() throws OrmException {
-    if (reviewDbUpdatesAreBlocked) {
-      throw new OrmException("Updates to groups in ReviewDb are blocked");
-    }
-  }
-
   private void dispatchAuditEventsOnGroupCreation(InternalGroup createdGroup) {
     if (currentUser == null) {
       return;
diff --git a/java/com/google/gerrit/server/group/db/InternalGroupUpdate.java b/java/com/google/gerrit/server/group/db/InternalGroupUpdate.java
index db4e990..5ce3c1c 100644
--- a/java/com/google/gerrit/server/group/db/InternalGroupUpdate.java
+++ b/java/com/google/gerrit/server/group/db/InternalGroupUpdate.java
@@ -145,7 +145,7 @@
      * #setMemberModification(MemberModification)} in order to combine multiple member additions,
      * deletions, or other modifications into one update.
      */
-    abstract MemberModification getMemberModification();
+    public abstract MemberModification getMemberModification();
 
     /** @see #getSubgroupModification() */
     public abstract Builder setSubgroupModification(SubgroupModification subgroupModification);
@@ -158,7 +158,7 @@
      * #setSubgroupModification(SubgroupModification)} in order to combine multiple subgroup
      * additions, deletions, or other modifications into one update.
      */
-    abstract SubgroupModification getSubgroupModification();
+    public abstract SubgroupModification getSubgroupModification();
 
     /** @see #getUpdatedOn() */
     public abstract Builder setUpdatedOn(Timestamp timestamp);
diff --git a/java/com/google/gerrit/server/group/db/testing/GroupTestUtil.java b/java/com/google/gerrit/server/group/db/testing/GroupTestUtil.java
index 9197a01..5a0d28c 100644
--- a/java/com/google/gerrit/server/group/db/testing/GroupTestUtil.java
+++ b/java/com/google/gerrit/server/group/db/testing/GroupTestUtil.java
@@ -14,48 +14,17 @@
 
 package com.google.gerrit.server.group.db.testing;
 
-import static com.google.common.collect.ImmutableList.toImmutableList;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Streams;
-import com.google.gerrit.extensions.common.CommitInfo;
 import com.google.gerrit.server.config.AllUsersName;
-import com.google.gerrit.server.git.CommitUtil;
 import com.google.gerrit.server.git.GitRepositoryManager;
-import java.io.IOException;
 import org.eclipse.jgit.junit.TestRepository;
 import org.eclipse.jgit.lib.PersonIdent;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.RevCommit;
-import org.eclipse.jgit.revwalk.RevSort;
 import org.eclipse.jgit.revwalk.RevWalk;
 
 /** Test utilities for low-level NoteDb groups. */
 public class GroupTestUtil {
-  // TODO(dborowitz): Move somewhere even more common.
-  public static ImmutableList<CommitInfo> log(Repository repo, String refName) throws Exception {
-    try (RevWalk rw = new RevWalk(repo)) {
-      Ref ref = repo.exactRef(refName);
-      if (ref != null) {
-        rw.sort(RevSort.REVERSE);
-        rw.markStart(rw.parseCommit(ref.getObjectId()));
-        return Streams.stream(rw)
-            .map(
-                c -> {
-                  try {
-                    return CommitUtil.toCommitInfo(c);
-                  } catch (IOException e) {
-                    throw new IllegalStateException(
-                        "unexpected state when converting commit " + c.getName(), e);
-                  }
-                })
-            .collect(toImmutableList());
-      }
-    }
-    return ImmutableList.of();
-  }
-
   public static void updateGroupFile(
       GitRepositoryManager repoManager,
       AllUsersName allUsersName,
diff --git a/java/com/google/gerrit/server/index/DummyIndexModule.java b/java/com/google/gerrit/server/index/DummyIndexModule.java
index 211f9d1..8b450bc 100644
--- a/java/com/google/gerrit/server/index/DummyIndexModule.java
+++ b/java/com/google/gerrit/server/index/DummyIndexModule.java
@@ -17,14 +17,14 @@
 import com.google.gerrit.index.Index;
 import com.google.gerrit.index.IndexConfig;
 import com.google.gerrit.index.Schema;
+import com.google.gerrit.index.project.ProjectData;
+import com.google.gerrit.index.project.ProjectIndex;
 import com.google.gerrit.server.account.AccountState;
 import com.google.gerrit.server.group.InternalGroup;
 import com.google.gerrit.server.index.account.AccountIndex;
 import com.google.gerrit.server.index.change.ChangeIndex;
 import com.google.gerrit.server.index.change.DummyChangeIndex;
 import com.google.gerrit.server.index.group.GroupIndex;
-import com.google.gerrit.server.index.project.ProjectIndex;
-import com.google.gerrit.server.project.ProjectData;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.inject.AbstractModule;
 
diff --git a/java/com/google/gerrit/server/index/IndexModule.java b/java/com/google/gerrit/server/index/IndexModule.java
index 0c4a988..c069864 100644
--- a/java/com/google/gerrit/server/index/IndexModule.java
+++ b/java/com/google/gerrit/server/index/IndexModule.java
@@ -26,6 +26,10 @@
 import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.gerrit.index.IndexDefinition;
 import com.google.gerrit.index.SchemaDefinitions;
+import com.google.gerrit.index.project.ProjectIndexCollection;
+import com.google.gerrit.index.project.ProjectIndexRewriter;
+import com.google.gerrit.index.project.ProjectIndexer;
+import com.google.gerrit.index.project.ProjectSchemaDefinitions;
 import com.google.gerrit.lifecycle.LifecycleModule;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.git.WorkQueue;
@@ -46,12 +50,8 @@
 import com.google.gerrit.server.index.group.GroupIndexer;
 import com.google.gerrit.server.index.group.GroupIndexerImpl;
 import com.google.gerrit.server.index.group.GroupSchemaDefinitions;
-import com.google.gerrit.server.index.project.ProjectIndexCollection;
 import com.google.gerrit.server.index.project.ProjectIndexDefinition;
-import com.google.gerrit.server.index.project.ProjectIndexRewriter;
-import com.google.gerrit.server.index.project.ProjectIndexer;
 import com.google.gerrit.server.index.project.ProjectIndexerImpl;
-import com.google.gerrit.server.index.project.ProjectSchemaDefinitions;
 import com.google.inject.Inject;
 import com.google.inject.Injector;
 import com.google.inject.Key;
diff --git a/java/com/google/gerrit/server/index/IndexUtils.java b/java/com/google/gerrit/server/index/IndexUtils.java
index 2abe876..9836e82 100644
--- a/java/com/google/gerrit/server/index/IndexUtils.java
+++ b/java/com/google/gerrit/server/index/IndexUtils.java
@@ -23,11 +23,11 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
 import com.google.gerrit.index.QueryOptions;
+import com.google.gerrit.index.project.ProjectField;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.gerrit.server.index.account.AccountField;
 import com.google.gerrit.server.index.group.GroupField;
-import com.google.gerrit.server.index.project.ProjectField;
 import com.google.gerrit.server.query.change.SingleGroupUser;
 import java.io.IOException;
 import java.util.Set;
diff --git a/java/com/google/gerrit/server/index/account/AccountIndexerImpl.java b/java/com/google/gerrit/server/index/account/AccountIndexerImpl.java
index d055a46..b7bb0dd 100644
--- a/java/com/google/gerrit/server/index/account/AccountIndexerImpl.java
+++ b/java/com/google/gerrit/server/index/account/AccountIndexerImpl.java
@@ -14,11 +14,7 @@
 
 package com.google.gerrit.server.index.account;
 
-import static com.google.gerrit.server.git.QueueProvider.QueueType.BATCH;
-
 import com.google.common.collect.ImmutableSet;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.gerrit.common.Nullable;
 import com.google.gerrit.extensions.events.AccountIndexedListener;
 import com.google.gerrit.extensions.registration.DynamicSet;
@@ -26,17 +22,12 @@
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.account.AccountState;
-import com.google.gerrit.server.config.GerritServerConfig;
-import com.google.gerrit.server.index.IndexExecutor;
-import com.google.gerrit.server.index.IndexUtils;
 import com.google.inject.assistedinject.Assisted;
 import com.google.inject.assistedinject.AssistedInject;
 import java.io.IOException;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Optional;
-import java.util.concurrent.Future;
-import org.eclipse.jgit.lib.Config;
 
 public class AccountIndexerImpl implements AccountIndexer {
   public interface Factory {
@@ -48,8 +39,6 @@
   private final AccountCache byIdCache;
   private final DynamicSet<AccountIndexedListener> indexedListener;
   private final StalenessChecker stalenessChecker;
-  private final ListeningExecutorService batchExecutor;
-  private final boolean autoReindexIfStale;
   @Nullable private final AccountIndexCollection indexes;
   @Nullable private final AccountIndex index;
 
@@ -58,14 +47,10 @@
       AccountCache byIdCache,
       DynamicSet<AccountIndexedListener> indexedListener,
       StalenessChecker stalenessChecker,
-      @IndexExecutor(BATCH) ListeningExecutorService batchExecutor,
-      @GerritServerConfig Config config,
       @Assisted AccountIndexCollection indexes) {
     this.byIdCache = byIdCache;
     this.indexedListener = indexedListener;
     this.stalenessChecker = stalenessChecker;
-    this.batchExecutor = batchExecutor;
-    this.autoReindexIfStale = autoReindexIfStale(config);
     this.indexes = indexes;
     this.index = null;
   }
@@ -75,14 +60,10 @@
       AccountCache byIdCache,
       DynamicSet<AccountIndexedListener> indexedListener,
       StalenessChecker stalenessChecker,
-      @IndexExecutor(BATCH) ListeningExecutorService batchExecutor,
-      @GerritServerConfig Config config,
       @Assisted @Nullable AccountIndex index) {
     this.byIdCache = byIdCache;
     this.indexedListener = indexedListener;
     this.stalenessChecker = stalenessChecker;
-    this.batchExecutor = batchExecutor;
-    this.autoReindexIfStale = autoReindexIfStale(config);
     this.indexes = null;
     this.index = index;
   }
@@ -90,6 +71,8 @@
   @Override
   public void index(Account.Id id) throws IOException {
     for (Index<Account.Id, AccountState> i : getWriteIndexes()) {
+      // Evict the cache to get an up-to-date value for sure.
+      byIdCache.evict(id);
       Optional<AccountState> accountState = byIdCache.get(id);
       if (accountState.isPresent()) {
         i.replace(accountState.get());
@@ -98,7 +81,6 @@
       }
     }
     fireAccountIndexedEvent(id.get());
-    autoReindexIfStale(id);
   }
 
   @Override
@@ -110,35 +92,6 @@
     return false;
   }
 
-  private static boolean autoReindexIfStale(Config cfg) {
-    return cfg.getBoolean("index", null, "autoReindexIfStale", true);
-  }
-
-  private void autoReindexIfStale(Account.Id id) {
-    if (autoReindexIfStale) {
-      // Don't retry indefinitely; if this fails the account will be stale.
-      @SuppressWarnings("unused")
-      Future<?> possiblyIgnoredError = reindexIfStaleAsync(id);
-    }
-  }
-
-  /**
-   * Asynchronously check if a account is stale, and reindex if it is.
-   *
-   * <p>Always run on the batch executor, even if this indexer instance is configured to use a
-   * different executor.
-   *
-   * @param id the ID of the account.
-   * @return future for reindexing the account; returns true if the account was stale.
-   */
-  @SuppressWarnings("deprecation")
-  private com.google.common.util.concurrent.CheckedFuture<Boolean, IOException> reindexIfStaleAsync(
-      Account.Id id) {
-    return Futures.makeChecked(
-        Futures.nonCancellationPropagating(batchExecutor.submit(() -> reindexIfStale(id))),
-        IndexUtils.MAPPER);
-  }
-
   private void fireAccountIndexedEvent(int id) {
     for (AccountIndexedListener listener : indexedListener) {
       listener.onAccountIndexed(id);
diff --git a/java/com/google/gerrit/server/index/account/IndexedAccountQuery.java b/java/com/google/gerrit/server/index/account/IndexedAccountQuery.java
index e8b1861..644f1eb 100644
--- a/java/com/google/gerrit/server/index/account/IndexedAccountQuery.java
+++ b/java/com/google/gerrit/server/index/account/IndexedAccountQuery.java
@@ -14,21 +14,41 @@
 
 package com.google.gerrit.server.index.account;
 
+import static com.google.common.base.Preconditions.checkState;
+
 import com.google.gerrit.index.Index;
 import com.google.gerrit.index.IndexedQuery;
 import com.google.gerrit.index.QueryOptions;
 import com.google.gerrit.index.query.DataSource;
+import com.google.gerrit.index.query.Matchable;
 import com.google.gerrit.index.query.Predicate;
 import com.google.gerrit.index.query.QueryParseException;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.server.account.AccountState;
+import com.google.gwtorm.server.OrmException;
 
 public class IndexedAccountQuery extends IndexedQuery<Account.Id, AccountState>
-    implements DataSource<AccountState> {
+    implements DataSource<AccountState>, Matchable<AccountState> {
 
   public IndexedAccountQuery(
       Index<Account.Id, AccountState> index, Predicate<AccountState> pred, QueryOptions opts)
       throws QueryParseException {
     super(index, pred, opts.convertForBackend());
   }
+
+  @Override
+  public boolean match(AccountState accountState) throws OrmException {
+    Predicate<AccountState> pred = getChild(0);
+    checkState(
+        pred.isMatchable(),
+        "match invoked, but child predicate %s doesn't implement %s",
+        pred,
+        Matchable.class.getName());
+    return pred.asMatchable().match(accountState);
+  }
+
+  @Override
+  public int getCost() {
+    return 1;
+  }
 }
diff --git a/java/com/google/gerrit/server/index/change/AllChangesIndexer.java b/java/com/google/gerrit/server/index/change/AllChangesIndexer.java
index 599596f..54bf0dc 100644
--- a/java/com/google/gerrit/server/index/change/AllChangesIndexer.java
+++ b/java/com/google/gerrit/server/index/change/AllChangesIndexer.java
@@ -111,20 +111,24 @@
     SortedSet<ProjectHolder> projects = new TreeSet<>();
     int changeCount = 0;
     Stopwatch sw = Stopwatch.createStarted();
+    int projectsFailed = 0;
     for (Project.NameKey name : projectCache.all()) {
       try (Repository repo = repoManager.openRepository(name)) {
         long size = estimateSize(repo);
         changeCount += size;
         projects.add(new ProjectHolder(name, size));
       } catch (IOException e) {
-        log.error("Error collecting projects", e);
-        return new Result(sw, false, 0, 0);
+        log.error("Error collecting project {}", name, e);
+        projectsFailed++;
+        if (projectsFailed > projects.size() / 2) {
+          log.error("Over 50% of the projects could not be collected: aborted");
+          return new Result(sw, false, 0, 0);
+        }
       }
       pm.update(1);
     }
     pm.endTask();
     setTotalWork(changeCount);
-
     return indexAll(index, projects);
   }
 
diff --git a/java/com/google/gerrit/server/index/change/ReindexAfterRefUpdate.java b/java/com/google/gerrit/server/index/change/ReindexAfterRefUpdate.java
index 2e1da65..0b76b1e 100644
--- a/java/com/google/gerrit/server/index/change/ReindexAfterRefUpdate.java
+++ b/java/com/google/gerrit/server/index/change/ReindexAfterRefUpdate.java
@@ -32,6 +32,7 @@
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.git.QueueProvider.QueueType;
 import com.google.gerrit.server.index.IndexExecutor;
+import com.google.gerrit.server.index.account.AccountIndexer;
 import com.google.gerrit.server.notedb.ChangeNotes;
 import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.query.change.InternalChangeQuery;
@@ -59,6 +60,7 @@
   private final ChangeNotes.Factory notesFactory;
   private final AllUsersName allUsersName;
   private final AccountCache accountCache;
+  private final Provider<AccountIndexer> indexer;
   private final ListeningExecutorService executor;
   private final boolean enabled;
 
@@ -72,6 +74,7 @@
       ChangeNotes.Factory notesFactory,
       AllUsersName allUsersName,
       AccountCache accountCache,
+      Provider<AccountIndexer> indexer,
       @IndexExecutor(QueueType.BATCH) ListeningExecutorService executor) {
     this.requestContext = requestContext;
     this.queryProvider = queryProvider;
@@ -80,6 +83,7 @@
     this.notesFactory = notesFactory;
     this.allUsersName = allUsersName;
     this.accountCache = accountCache;
+    this.indexer = indexer;
     this.executor = executor;
     this.enabled = cfg.getBoolean("index", null, "reindexAfterRefUpdate", true);
   }
@@ -91,6 +95,7 @@
       if (accountId != null && !event.getRefName().startsWith(RefNames.REFS_STARRED_CHANGES)) {
         try {
           accountCache.evict(accountId);
+          indexer.get().index(accountId);
         } catch (IOException e) {
           log.error(String.format("Reindex account %s failed.", accountId), e);
         }
diff --git a/java/com/google/gerrit/server/index/project/AllProjectsIndexer.java b/java/com/google/gerrit/server/index/project/AllProjectsIndexer.java
index a53434e..1e36f18 100644
--- a/java/com/google/gerrit/server/index/project/AllProjectsIndexer.java
+++ b/java/com/google/gerrit/server/index/project/AllProjectsIndexer.java
@@ -21,10 +21,11 @@
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.gerrit.index.SiteIndexer;
+import com.google.gerrit.index.project.ProjectData;
+import com.google.gerrit.index.project.ProjectIndex;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.index.IndexExecutor;
 import com.google.gerrit.server.project.ProjectCache;
-import com.google.gerrit.server.project.ProjectData;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import java.io.PrintWriter;
diff --git a/java/com/google/gerrit/server/index/project/ProjectIndexDefinition.java b/java/com/google/gerrit/server/index/project/ProjectIndexDefinition.java
index 301f209..ce2b634 100644
--- a/java/com/google/gerrit/server/index/project/ProjectIndexDefinition.java
+++ b/java/com/google/gerrit/server/index/project/ProjectIndexDefinition.java
@@ -16,8 +16,11 @@
 
 import com.google.gerrit.common.Nullable;
 import com.google.gerrit.index.IndexDefinition;
+import com.google.gerrit.index.project.ProjectData;
+import com.google.gerrit.index.project.ProjectIndex;
+import com.google.gerrit.index.project.ProjectIndexCollection;
+import com.google.gerrit.index.project.ProjectSchemaDefinitions;
 import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.server.project.ProjectData;
 import com.google.inject.Inject;
 
 public class ProjectIndexDefinition
diff --git a/java/com/google/gerrit/server/index/project/ProjectIndexerImpl.java b/java/com/google/gerrit/server/index/project/ProjectIndexerImpl.java
index 9076648..a79bb7a 100644
--- a/java/com/google/gerrit/server/index/project/ProjectIndexerImpl.java
+++ b/java/com/google/gerrit/server/index/project/ProjectIndexerImpl.java
@@ -18,9 +18,12 @@
 import com.google.gerrit.common.Nullable;
 import com.google.gerrit.extensions.events.ProjectIndexedListener;
 import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.index.project.ProjectData;
+import com.google.gerrit.index.project.ProjectIndex;
+import com.google.gerrit.index.project.ProjectIndexCollection;
+import com.google.gerrit.index.project.ProjectIndexer;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.project.ProjectCache;
-import com.google.gerrit.server.project.ProjectData;
 import com.google.gerrit.server.project.ProjectState;
 import com.google.inject.assistedinject.Assisted;
 import com.google.inject.assistedinject.AssistedInject;
diff --git a/java/com/google/gerrit/server/mail/receive/MailProcessor.java b/java/com/google/gerrit/server/mail/receive/MailProcessor.java
index 9917261..949cd82 100644
--- a/java/com/google/gerrit/server/mail/receive/MailProcessor.java
+++ b/java/com/google/gerrit/server/mail/receive/MailProcessor.java
@@ -46,6 +46,7 @@
 import com.google.gerrit.server.mail.send.InboundEmailRejectionSender;
 import com.google.gerrit.server.notedb.ChangeNotes;
 import com.google.gerrit.server.patch.PatchListCache;
+import com.google.gerrit.server.patch.PatchListNotAvailableException;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gerrit.server.query.change.InternalChangeQuery;
 import com.google.gerrit.server.update.BatchUpdate;
@@ -274,7 +275,7 @@
 
     @Override
     public boolean updateChange(ChangeContext ctx)
-        throws OrmException, UnprocessableEntityException {
+        throws OrmException, UnprocessableEntityException, PatchListNotAvailableException {
       patchSet = psUtil.get(ctx.getDb(), ctx.getNotes(), psId);
       notes = ctx.getNotes();
       if (patchSet == null) {
@@ -371,7 +372,7 @@
 
     private Comment persistentCommentFromMailComment(
         ChangeContext ctx, MailComment mailComment, PatchSet patchSetForComment)
-        throws OrmException, UnprocessableEntityException {
+        throws OrmException, UnprocessableEntityException, PatchListNotAvailableException {
       String fileName;
       // The patch set that this comment is based on is different if this
       // comment was sent in reply to a comment on a previous patch set.
diff --git a/java/com/google/gerrit/server/mail/send/EmailArguments.java b/java/com/google/gerrit/server/mail/send/EmailArguments.java
index 83a1c25..04f4d6c 100644
--- a/java/com/google/gerrit/server/mail/send/EmailArguments.java
+++ b/java/com/google/gerrit/server/mail/send/EmailArguments.java
@@ -27,6 +27,8 @@
 import com.google.gerrit.server.config.AllProjectsName;
 import com.google.gerrit.server.config.AnonymousCowardName;
 import com.google.gerrit.server.config.CanonicalWebUrl;
+import com.google.gerrit.server.config.GerritInstanceName;
+import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.mail.EmailSettings;
@@ -44,6 +46,7 @@
 import com.google.inject.Provider;
 import com.google.template.soy.tofu.SoyTofu;
 import java.util.List;
+import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.PersonIdent;
 
 public class EmailArguments {
@@ -75,6 +78,8 @@
   final DynamicSet<OutgoingEmailValidationListener> outgoingEmailValidationListeners;
   final Provider<InternalAccountQuery> accountQueryProvider;
   final OutgoingEmailValidator validator;
+  final boolean addInstanceNameInSubject;
+  final Provider<String> instanceNameProvider;
 
   @Inject
   EmailArguments(
@@ -104,7 +109,9 @@
       SitePaths site,
       DynamicSet<OutgoingEmailValidationListener> outgoingEmailValidationListeners,
       Provider<InternalAccountQuery> accountQueryProvider,
-      OutgoingEmailValidator validator) {
+      OutgoingEmailValidator validator,
+      @GerritInstanceName Provider<String> instanceNameProvider,
+      @GerritServerConfig Config cfg) {
     this.server = server;
     this.projectCache = projectCache;
     this.permissionBackend = permissionBackend;
@@ -132,5 +139,8 @@
     this.outgoingEmailValidationListeners = outgoingEmailValidationListeners;
     this.accountQueryProvider = accountQueryProvider;
     this.validator = validator;
+    this.instanceNameProvider = instanceNameProvider;
+
+    this.addInstanceNameInSubject = cfg.getBoolean("sendemail", "addInstanceNameInSubject", false);
   }
 }
diff --git a/java/com/google/gerrit/server/mail/send/NotificationEmail.java b/java/com/google/gerrit/server/mail/send/NotificationEmail.java
index f657fb0..d182ecd 100644
--- a/java/com/google/gerrit/server/mail/send/NotificationEmail.java
+++ b/java/com/google/gerrit/server/mail/send/NotificationEmail.java
@@ -109,6 +109,11 @@
     soyContext.put("projectName", projectName);
     // shortProjectName is the project name with the path abbreviated.
     soyContext.put("shortProjectName", projectName.replaceAll("/.*/", "..."));
+    // instanceAndProjectName is the instance's name followed by the abbreviated project path
+    soyContext.put(
+        "instanceAndProjectName",
+        getInstanceAndProjectName(args.instanceNameProvider.get(), projectName));
+    soyContext.put("addInstanceNameInSubject", args.addInstanceNameInSubject);
 
     soyContextEmailData.put("sshHost", getSshHost());
 
@@ -119,4 +124,14 @@
     footers.add(MailHeader.PROJECT.withDelimiter() + branch.getParentKey().get());
     footers.add("Gerrit-Branch: " + branch.getShortName());
   }
+
+  protected static String getInstanceAndProjectName(String instanceName, String projectName) {
+    if (instanceName == null || instanceName.isEmpty()) {
+      return projectName.replaceAll("/.*/", "...");
+    }
+
+    // Extract the project name (everything after the last slash) and prepends it with gerrit's
+    // instance name
+    return instanceName + "/" + projectName.substring(projectName.lastIndexOf("/") + 1);
+  }
 }
diff --git a/java/com/google/gerrit/server/mail/send/OutgoingEmail.java b/java/com/google/gerrit/server/mail/send/OutgoingEmail.java
index b882089..0f3bcdb 100644
--- a/java/com/google/gerrit/server/mail/send/OutgoingEmail.java
+++ b/java/com/google/gerrit/server/mail/send/OutgoingEmail.java
@@ -60,7 +60,7 @@
   private static final Logger log = LoggerFactory.getLogger(OutgoingEmail.class);
 
   protected String messageClass;
-  private final HashSet<Account.Id> rcptTo = new HashSet<>();
+  private final Set<Account.Id> rcptTo = new HashSet<>();
   private final Map<String, EmailHeader> headers;
   private final Set<Address> smtpRcptTo = new HashSet<>();
   private Address smtpFromAddress;
@@ -541,11 +541,16 @@
 
     soyContextEmailData = new HashMap<>();
     soyContextEmailData.put("settingsUrl", getSettingsUrl());
+    soyContextEmailData.put("instanceName", getInstanceName());
     soyContextEmailData.put("gerritHost", getGerritHost());
     soyContextEmailData.put("gerritUrl", getGerritUrl());
     soyContext.put("email", soyContextEmailData);
   }
 
+  private String getInstanceName() {
+    return args.instanceNameProvider.get();
+  }
+
   private String soyTemplate(String name, SanitizedContent.ContentKind kind) {
     return args.soyTofu
         .newRenderer("com.google.gerrit.server.mail.template." + name)
diff --git a/java/com/google/gerrit/server/notedb/NoteDbUpdateManager.java b/java/com/google/gerrit/server/notedb/NoteDbUpdateManager.java
index b9f5fe6..c599c8e 100644
--- a/java/com/google/gerrit/server/notedb/NoteDbUpdateManager.java
+++ b/java/com/google/gerrit/server/notedb/NoteDbUpdateManager.java
@@ -454,7 +454,11 @@
         update.getProjectName(),
         projectName);
     checkState(staged == null, "cannot add new update after staging");
-    changeUpdates.put(update.getRefName(), update);
+    checkArgument(
+        !rewriters.containsKey(update.getRefName()),
+        "cannot update & rewrite ref %s in one BatchUpdate",
+        update.getRefName());
+
     ChangeDraftUpdate du = update.getDraftUpdate();
     if (du != null) {
       draftUpdates.put(du.getRefName(), du);
@@ -463,10 +467,17 @@
     if (rcu != null) {
       robotCommentUpdates.put(rcu.getRefName(), rcu);
     }
-    DeleteCommentRewriter deleteCommentRewriter = update.getDeleteCommentRewriter();
-    if (deleteCommentRewriter != null) {
-      rewriters.put(deleteCommentRewriter.getRefName(), deleteCommentRewriter);
+    DeleteCommentRewriter rwt = update.getDeleteCommentRewriter();
+    if (rwt != null) {
+      // Checks whether there is any ChangeUpdate added earlier trying to update the same ref.
+      checkArgument(
+          !changeUpdates.containsKey(rwt.getRefName()),
+          "cannot update & rewrite ref %s in one BatchUpdate",
+          rwt.getRefName());
+      rewriters.put(rwt.getRefName(), rwt);
     }
+
+    changeUpdates.put(update.getRefName(), update);
   }
 
   public void add(ChangeDraftUpdate draftUpdate) {
@@ -695,17 +706,6 @@
       addUpdates(robotCommentUpdates, changeRepo);
     }
     if (!rewriters.isEmpty()) {
-      Optional<String> conflictKey =
-          rewriters
-              .keySet()
-              .stream()
-              .filter(k -> (draftUpdates.containsKey(k) || robotCommentUpdates.containsKey(k)))
-              .findAny();
-      if (conflictKey.isPresent()) {
-        throw new IllegalArgumentException(
-            String.format(
-                "cannot update and rewrite ref %s in one BatchUpdate", conflictKey.get()));
-      }
       addRewrites(rewriters, changeRepo);
     }
 
diff --git a/java/com/google/gerrit/server/notedb/PrimaryStorageMigrator.java b/java/com/google/gerrit/server/notedb/PrimaryStorageMigrator.java
index e33ece9..69cc2eb 100644
--- a/java/com/google/gerrit/server/notedb/PrimaryStorageMigrator.java
+++ b/java/com/google/gerrit/server/notedb/PrimaryStorageMigrator.java
@@ -80,6 +80,18 @@
 public class PrimaryStorageMigrator {
   private static final Logger log = LoggerFactory.getLogger(PrimaryStorageMigrator.class);
 
+  /**
+   * Exception thrown during migration if the change has no {@code noteDbState} field at the
+   * beginning of the migration.
+   */
+  public static class NoNoteDbStateException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    private NoNoteDbStateException(Change.Id id) {
+      super("change " + id + " has no note_db_state; rebuild it first");
+    }
+  }
+
   private final AllUsersName allUsers;
   private final ChangeNotes.Factory changeNotesFactory;
   private final ChangeRebuilder rebuilder;
@@ -280,9 +292,11 @@
                     NoteDbChangeState state = NoteDbChangeState.parse(change);
                     if (state == null) {
                       // Could rebuild the change here, but that's more complexity, and this
-                      // really shouldn't happen.
-                      throw new OrmRuntimeException(
-                          "change " + id + " has no note_db_state; rebuild it first");
+                      // normally shouldn't happen.
+                      //
+                      // Known cases where this happens are described in and handled by
+                      // NoteDbMigrator#canSkipPrimaryStorageMigration.
+                      throw new NoNoteDbStateException(id);
                     }
                     // If the change is already read-only, then the lease is held by another
                     // (likely failed) migrator thread. Fail early, as we can't take over
diff --git a/java/com/google/gerrit/server/notedb/rebuild/ChangeRebuilderImpl.java b/java/com/google/gerrit/server/notedb/rebuild/ChangeRebuilderImpl.java
index 9ab06e8..92a878c 100644
--- a/java/com/google/gerrit/server/notedb/rebuild/ChangeRebuilderImpl.java
+++ b/java/com/google/gerrit/server/notedb/rebuild/ChangeRebuilderImpl.java
@@ -522,8 +522,7 @@
   }
 
   private void flushEventsToDraftUpdate(
-      NoteDbUpdateManager manager, EventList<DraftCommentEvent> events, Change change)
-      throws OrmException {
+      NoteDbUpdateManager manager, EventList<DraftCommentEvent> events, Change change) {
     if (events.isEmpty()) {
       return;
     }
diff --git a/java/com/google/gerrit/server/notedb/rebuild/CommentEvent.java b/java/com/google/gerrit/server/notedb/rebuild/CommentEvent.java
index c8a649e..611f32e 100644
--- a/java/com/google/gerrit/server/notedb/rebuild/CommentEvent.java
+++ b/java/com/google/gerrit/server/notedb/rebuild/CommentEvent.java
@@ -24,9 +24,13 @@
 import com.google.gerrit.server.CommentsUtil;
 import com.google.gerrit.server.notedb.ChangeUpdate;
 import com.google.gerrit.server.patch.PatchListCache;
-import com.google.gwtorm.server.OrmException;
+import com.google.gerrit.server.patch.PatchListNotAvailableException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 class CommentEvent extends Event {
+  private static final Logger log = LoggerFactory.getLogger(CommentEvent.class);
+
   public final Comment c;
   private final Change change;
   private final PatchSet ps;
@@ -57,10 +61,19 @@
   }
 
   @Override
-  void apply(ChangeUpdate update) throws OrmException {
+  void apply(ChangeUpdate update) {
     checkUpdate(update);
     if (c.revId == null) {
-      setCommentRevId(c, cache, change, ps);
+      try {
+        setCommentRevId(c, cache, change, ps);
+      } catch (PatchListNotAvailableException e) {
+        log.warn(
+            "Unable to determine parent commit of patch set {} ({}); omitting inline comment",
+            ps.getId(),
+            ps.getRevision(),
+            c);
+        return;
+      }
     }
     update.putComment(PatchLineComment.Status.PUBLISHED, c);
   }
diff --git a/java/com/google/gerrit/server/notedb/rebuild/DraftCommentEvent.java b/java/com/google/gerrit/server/notedb/rebuild/DraftCommentEvent.java
index 914930c..3bc3a58 100644
--- a/java/com/google/gerrit/server/notedb/rebuild/DraftCommentEvent.java
+++ b/java/com/google/gerrit/server/notedb/rebuild/DraftCommentEvent.java
@@ -24,9 +24,13 @@
 import com.google.gerrit.server.notedb.ChangeDraftUpdate;
 import com.google.gerrit.server.notedb.ChangeUpdate;
 import com.google.gerrit.server.patch.PatchListCache;
-import com.google.gwtorm.server.OrmException;
+import com.google.gerrit.server.patch.PatchListNotAvailableException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 class DraftCommentEvent extends Event {
+  private static final Logger log = LoggerFactory.getLogger(DraftCommentEvent.class);
+
   public final Comment c;
   private final Change change;
   private final PatchSet ps;
@@ -56,9 +60,18 @@
     throw new UnsupportedOperationException();
   }
 
-  void applyDraft(ChangeDraftUpdate draftUpdate) throws OrmException {
+  void applyDraft(ChangeDraftUpdate draftUpdate) {
     if (c.revId == null) {
-      setCommentRevId(c, cache, change, ps);
+      try {
+        setCommentRevId(c, cache, change, ps);
+      } catch (PatchListNotAvailableException e) {
+        log.warn(
+            "Unable to determine parent commit of patch set {} ({}); omitting draft inline comment",
+            ps.getId(),
+            ps.getRevision(),
+            c);
+        return;
+      }
     }
     draftUpdate.putComment(c);
   }
diff --git a/java/com/google/gerrit/server/notedb/rebuild/NoteDbMigrator.java b/java/com/google/gerrit/server/notedb/rebuild/NoteDbMigrator.java
index 8e8f232..c11aeef 100644
--- a/java/com/google/gerrit/server/notedb/rebuild/NoteDbMigrator.java
+++ b/java/com/google/gerrit/server/notedb/rebuild/NoteDbMigrator.java
@@ -33,6 +33,7 @@
 import com.google.common.base.Stopwatch;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableListMultimap;
+import com.google.common.collect.Iterables;
 import com.google.common.collect.MultimapBuilder;
 import com.google.common.collect.Ordering;
 import com.google.common.collect.SetMultimap;
@@ -66,6 +67,7 @@
 import com.google.gerrit.server.notedb.NoteDbUpdateManager;
 import com.google.gerrit.server.notedb.NotesMigrationState;
 import com.google.gerrit.server.notedb.PrimaryStorageMigrator;
+import com.google.gerrit.server.notedb.PrimaryStorageMigrator.NoNoteDbStateException;
 import com.google.gerrit.server.notedb.RepoSequence;
 import com.google.gerrit.server.notedb.rebuild.ChangeRebuilder.NoPatchSetsException;
 import com.google.gerrit.server.project.NoSuchChangeException;
@@ -605,7 +607,19 @@
                       executor.submit(
                           () -> {
                             try (ManualRequestContext ctx = contextHelper.open()) {
-                              primaryStorageMigrator.migrateToNoteDbPrimary(id);
+                              try {
+                                primaryStorageMigrator.migrateToNoteDbPrimary(id);
+                              } catch (NoNoteDbStateException e) {
+                                if (canSkipPrimaryStorageMigration(
+                                    ctx.getReviewDbProvider().get(), id)) {
+                                  log.warn(
+                                      "Change {} previously failed to rebuild;"
+                                          + " skipping primary storage migration",
+                                      e);
+                                } else {
+                                  throw e;
+                                }
+                              }
                               return true;
                             } catch (Exception e) {
                               log.error("Error migrating primary storage for " + id, e);
@@ -628,6 +642,38 @@
     return disableReviewDb(prev);
   }
 
+  /**
+   * Checks whether a change is so corrupt that it can be completely skipped by the primary storage
+   * migration step.
+   *
+   * <p>To get to the point where this method is called from {@link #setNoteDbPrimary}, it means we
+   * attempted to rebuild it, and encountered an error that was then caught in {@link
+   * #rebuildProject} and skipped. As a result, there is no {@code noteDbState} field in the change
+   * by the time we get to {@link #setNoteDbPrimary}, so {@code migrateToNoteDbPrimary} throws an
+   * exception.
+   *
+   * <p>We have to do this hacky double-checking because we don't have a way for the rebuilding
+   * phase to communicate to the primary storage migration phase that the change is skippable. It
+   * would be possible to store this info in some field in this class, but there is no guarantee
+   * that the rebuild and primary storage migration phases are run in the same JVM invocation.
+   *
+   * <p>In an ideal world, we could do this through the {@link
+   * com.google.gerrit.server.notedb.NoteDbChangeState.PrimaryStorage} enum, having a separate value
+   * for errors. However, that would be an invasive change touching many non-migration-related parts
+   * of the NoteDb migration code, which is too risky to attempt in the stable branch where this bug
+   * had to be fixed.
+   *
+   * <p>As of this writing, the only case where this happens is when a change has no patch sets.
+   */
+  private static boolean canSkipPrimaryStorageMigration(ReviewDb db, Change.Id id) {
+    try {
+      return Iterables.isEmpty(unwrapDb(db).patchSets().byChange(id));
+    } catch (Exception e) {
+      log.error("Error checking if change " + id + " can be skipped, assuming no", e);
+      return false;
+    }
+  }
+
   private NotesMigrationState disableReviewDb(NotesMigrationState prev) throws IOException {
     return saveState(prev, NOTE_DB, c -> setAutoMigrate(c, false));
   }
diff --git a/java/com/google/gerrit/server/patch/DiffSummaryKey.java b/java/com/google/gerrit/server/patch/DiffSummaryKey.java
index 94c793b9..0f4757a 100644
--- a/java/com/google/gerrit/server/patch/DiffSummaryKey.java
+++ b/java/com/google/gerrit/server/patch/DiffSummaryKey.java
@@ -15,7 +15,9 @@
 package com.google.gerrit.server.patch;
 
 import static org.eclipse.jgit.lib.ObjectIdSerializer.read;
+import static org.eclipse.jgit.lib.ObjectIdSerializer.readWithoutMarker;
 import static org.eclipse.jgit.lib.ObjectIdSerializer.write;
+import static org.eclipse.jgit.lib.ObjectIdSerializer.writeWithoutMarker;
 
 import com.google.common.base.Preconditions;
 import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
@@ -93,7 +95,7 @@
   private void writeObject(ObjectOutputStream out) throws IOException {
     write(out, oldId);
     out.writeInt(parentNum == null ? 0 : parentNum);
-    write(out, newId);
+    writeWithoutMarker(out, newId);
     Character c = PatchListKey.WHITESPACE_TYPES.get(whitespace);
     if (c == null) {
       throw new IOException("Invalid whitespace type: " + whitespace);
@@ -105,7 +107,7 @@
     oldId = read(in);
     int n = in.readInt();
     parentNum = n == 0 ? null : Integer.valueOf(n);
-    newId = read(in);
+    newId = readWithoutMarker(in);
     char t = in.readChar();
     whitespace = PatchListKey.WHITESPACE_TYPES.inverse().get(t);
     if (whitespace == null) {
diff --git a/java/com/google/gerrit/server/patch/PatchList.java b/java/com/google/gerrit/server/patch/PatchList.java
index 928e8b4..cf5df4a 100644
--- a/java/com/google/gerrit/server/patch/PatchList.java
+++ b/java/com/google/gerrit/server/patch/PatchList.java
@@ -19,7 +19,9 @@
 import static com.google.gerrit.server.ioutil.BasicSerialization.writeBytes;
 import static com.google.gerrit.server.ioutil.BasicSerialization.writeVarInt32;
 import static org.eclipse.jgit.lib.ObjectIdSerializer.read;
+import static org.eclipse.jgit.lib.ObjectIdSerializer.readWithoutMarker;
 import static org.eclipse.jgit.lib.ObjectIdSerializer.write;
+import static org.eclipse.jgit.lib.ObjectIdSerializer.writeWithoutMarker;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.gerrit.common.Nullable;
@@ -172,7 +174,7 @@
     final ByteArrayOutputStream buf = new ByteArrayOutputStream();
     try (DeflaterOutputStream out = new DeflaterOutputStream(buf)) {
       write(out, oldId);
-      write(out, newId);
+      writeWithoutMarker(out, newId);
       writeVarInt32(out, isMerge ? 1 : 0);
       comparisonType.writeTo(out);
       writeVarInt32(out, insertions);
@@ -189,7 +191,7 @@
     final ByteArrayInputStream buf = new ByteArrayInputStream(readBytes(input));
     try (InflaterInputStream in = new InflaterInputStream(buf)) {
       oldId = read(in);
-      newId = read(in);
+      newId = readWithoutMarker(in);
       isMerge = readVarInt32(in) != 0;
       comparisonType = ComparisonType.readFrom(in);
       insertions = readVarInt32(in);
diff --git a/java/com/google/gerrit/server/patch/PatchListKey.java b/java/com/google/gerrit/server/patch/PatchListKey.java
index 3588d85..e5be70c 100644
--- a/java/com/google/gerrit/server/patch/PatchListKey.java
+++ b/java/com/google/gerrit/server/patch/PatchListKey.java
@@ -16,7 +16,9 @@
 
 import static com.google.common.base.Preconditions.checkState;
 import static org.eclipse.jgit.lib.ObjectIdSerializer.read;
+import static org.eclipse.jgit.lib.ObjectIdSerializer.readWithoutMarker;
 import static org.eclipse.jgit.lib.ObjectIdSerializer.write;
+import static org.eclipse.jgit.lib.ObjectIdSerializer.writeWithoutMarker;
 
 import com.google.common.collect.ImmutableBiMap;
 import com.google.gerrit.common.Nullable;
@@ -186,7 +188,7 @@
   private void writeObject(ObjectOutputStream out) throws IOException {
     write(out, oldId);
     out.writeInt(parentNum == null ? 0 : parentNum);
-    write(out, newId);
+    writeWithoutMarker(out, newId);
     Character c = WHITESPACE_TYPES.get(whitespace);
     if (c == null) {
       throw new IOException("Invalid whitespace type: " + whitespace);
@@ -199,7 +201,7 @@
     oldId = read(in);
     int n = in.readInt();
     parentNum = n == 0 ? null : Integer.valueOf(n);
-    newId = read(in);
+    newId = readWithoutMarker(in);
     char t = in.readChar();
     whitespace = WHITESPACE_TYPES.inverse().get(t);
     if (whitespace == null) {
diff --git a/java/com/google/gerrit/server/permissions/DefaultRefFilter.java b/java/com/google/gerrit/server/permissions/DefaultRefFilter.java
index 28695b8..84a3d87 100644
--- a/java/com/google/gerrit/server/permissions/DefaultRefFilter.java
+++ b/java/com/google/gerrit/server/permissions/DefaultRefFilter.java
@@ -114,7 +114,8 @@
     PermissionBackend.WithUser withUser = permissionBackend.user(user);
     PermissionBackend.ForProject forProject = withUser.project(projectState.getNameKey());
     if (!projectState.isAllUsers()) {
-      if (checkProjectPermission(forProject, ProjectPermission.READ)) {
+      if (projectState.statePermitsRead()
+          && checkProjectPermission(forProject, ProjectPermission.READ)) {
         return refs;
       } else if (projectControl.allRefsAreVisible(ImmutableSet.of(RefNames.REFS_CONFIG))) {
         return fastHideRefsMetaConfig(refs);
diff --git a/java/com/google/gerrit/server/permissions/ProjectControl.java b/java/com/google/gerrit/server/permissions/ProjectControl.java
index 00c3948..30ed180 100644
--- a/java/com/google/gerrit/server/permissions/ProjectControl.java
+++ b/java/com/google/gerrit/server/permissions/ProjectControl.java
@@ -404,7 +404,7 @@
               || isOwner();
 
         case READ:
-          return !isHidden() && allRefsAreVisible(Collections.emptySet());
+          return allRefsAreVisible(Collections.emptySet());
 
         case CREATE_REF:
           return canAddRefs();
diff --git a/java/com/google/gerrit/server/permissions/ProjectRef.java b/java/com/google/gerrit/server/permissions/ProjectRef.java
deleted file mode 100644
index deb224e..0000000
--- a/java/com/google/gerrit/server/permissions/ProjectRef.java
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (C) 2013 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.server.permissions;
-
-import com.google.auto.value.AutoValue;
-import com.google.gerrit.reviewdb.client.Project;
-
-@AutoValue
-abstract class ProjectRef {
-  public abstract Project.NameKey project();
-
-  public abstract String ref();
-
-  static ProjectRef create(Project.NameKey project, String ref) {
-    return new AutoValue_ProjectRef(project, ref);
-  }
-}
diff --git a/java/com/google/gerrit/server/project/ProjectCacheImpl.java b/java/com/google/gerrit/server/project/ProjectCacheImpl.java
index 68270e2..be13729 100644
--- a/java/com/google/gerrit/server/project/ProjectCacheImpl.java
+++ b/java/com/google/gerrit/server/project/ProjectCacheImpl.java
@@ -22,6 +22,7 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSortedSet;
 import com.google.common.collect.Sets;
+import com.google.gerrit.index.project.ProjectIndexer;
 import com.google.gerrit.lifecycle.LifecycleModule;
 import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.reviewdb.client.Project;
@@ -30,7 +31,6 @@
 import com.google.gerrit.server.config.AllUsersName;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.ProjectConfig;
-import com.google.gerrit.server.index.project.ProjectIndexer;
 import com.google.inject.Inject;
 import com.google.inject.Module;
 import com.google.inject.Provider;
@@ -155,6 +155,7 @@
         Throwables.throwIfInstanceOf(e.getCause(), IOException.class);
         throw new IOException(e);
       }
+      log.warn("Cannot find project {}", projectName.get(), e);
       return null;
     }
   }
diff --git a/java/com/google/gerrit/server/git/ProjectLevelConfig.java b/java/com/google/gerrit/server/project/ProjectLevelConfig.java
similarity index 61%
rename from java/com/google/gerrit/server/git/ProjectLevelConfig.java
rename to java/com/google/gerrit/server/project/ProjectLevelConfig.java
index 18dcef8..ee1bbef 100644
--- a/java/com/google/gerrit/server/git/ProjectLevelConfig.java
+++ b/java/com/google/gerrit/server/project/ProjectLevelConfig.java
@@ -12,14 +12,18 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.git;
+package com.google.gerrit.server.project;
+
+import static java.util.stream.Collectors.toList;
 
 import com.google.common.collect.Iterables;
+import com.google.common.collect.Streams;
 import com.google.gerrit.reviewdb.client.RefNames;
-import com.google.gerrit.server.project.ProjectState;
+import com.google.gerrit.server.git.VersionedMetaData;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Set;
+import java.util.stream.Stream;
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.CommitBuilder;
 import org.eclipse.jgit.lib.Config;
@@ -53,6 +57,22 @@
   }
 
   public Config getWithInheritance() {
+    return getWithInheritance(false);
+  }
+
+  /**
+   * Get a Config that includes the values from all parent projects.
+   *
+   * <p>Merging means that matching sections/subsection will be merged to include the values from
+   * both parent and child config.
+   *
+   * <p>No merging means that matching sections/subsections in the child project will replace the
+   * corresponding value from the parent.
+   *
+   * @param merge whether to merge parent values with child values or not.
+   * @return a combined config.
+   */
+  public Config getWithInheritance(boolean merge) {
     Config cfgWithInheritance = new Config();
     try {
       cfgWithInheritance.fromText(get().toText());
@@ -65,21 +85,41 @@
       for (String section : parentCfg.getSections()) {
         Set<String> allNames = get().getNames(section);
         for (String name : parentCfg.getNames(section)) {
+          String[] parentValues = parentCfg.getStringList(section, null, name);
           if (!allNames.contains(name)) {
+            cfgWithInheritance.setStringList(section, null, name, Arrays.asList(parentValues));
+          } else if (merge) {
             cfgWithInheritance.setStringList(
-                section, null, name, Arrays.asList(parentCfg.getStringList(section, null, name)));
+                section,
+                null,
+                name,
+                Stream.concat(
+                        Arrays.stream(cfg.getStringList(section, null, name)),
+                        Arrays.stream(parentValues))
+                    .sorted()
+                    .distinct()
+                    .collect(toList()));
           }
         }
 
         for (String subsection : parentCfg.getSubsections(section)) {
           allNames = get().getNames(section, subsection);
           for (String name : parentCfg.getNames(section, subsection)) {
+            String[] parentValues = parentCfg.getStringList(section, subsection, name);
             if (!allNames.contains(name)) {
               cfgWithInheritance.setStringList(
+                  section, subsection, name, Arrays.asList(parentValues));
+            } else if (merge) {
+              cfgWithInheritance.setStringList(
                   section,
                   subsection,
                   name,
-                  Arrays.asList(parentCfg.getStringList(section, subsection, name)));
+                  Streams.concat(
+                          Arrays.stream(cfg.getStringList(section, subsection, name)),
+                          Arrays.stream(parentValues))
+                      .sorted()
+                      .distinct()
+                      .collect(toList()));
             }
           }
         }
diff --git a/java/com/google/gerrit/server/project/ProjectState.java b/java/com/google/gerrit/server/project/ProjectState.java
index b70a520..2ef7891 100644
--- a/java/com/google/gerrit/server/project/ProjectState.java
+++ b/java/com/google/gerrit/server/project/ProjectState.java
@@ -33,6 +33,7 @@
 import com.google.gerrit.extensions.api.projects.ThemeInfo;
 import com.google.gerrit.extensions.client.SubmitType;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
+import com.google.gerrit.index.project.ProjectData;
 import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.reviewdb.client.BooleanProjectConfig;
 import com.google.gerrit.reviewdb.client.Branch;
@@ -46,7 +47,6 @@
 import com.google.gerrit.server.git.BranchOrderSection;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.ProjectConfig;
-import com.google.gerrit.server.git.ProjectLevelConfig;
 import com.google.gerrit.server.notedb.ChangeNotes;
 import com.google.gerrit.server.rules.PrologEnvironment;
 import com.google.gerrit.server.rules.RulesCache;
diff --git a/java/com/google/gerrit/server/query/account/AccountPredicates.java b/java/com/google/gerrit/server/query/account/AccountPredicates.java
index e643470..acb963c 100644
--- a/java/com/google/gerrit/server/query/account/AccountPredicates.java
+++ b/java/com/google/gerrit/server/query/account/AccountPredicates.java
@@ -19,12 +19,15 @@
 import com.google.gerrit.index.FieldDef;
 import com.google.gerrit.index.Schema;
 import com.google.gerrit.index.query.IndexPredicate;
+import com.google.gerrit.index.query.Matchable;
 import com.google.gerrit.index.query.Predicate;
 import com.google.gerrit.index.query.QueryBuilder;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.account.AccountState;
 import com.google.gerrit.server.index.account.AccountField;
+import com.google.gerrit.server.notedb.ChangeNotes;
+import com.google.gwtorm.server.OrmException;
 import java.util.List;
 
 public class AccountPredicates {
@@ -121,7 +124,14 @@
     return new AccountPredicate(AccountField.WATCHED_PROJECT, project.get());
   }
 
-  static class AccountPredicate extends IndexPredicate<AccountState> {
+  public static Predicate<AccountState> cansee(
+      AccountQueryBuilder.Arguments args, ChangeNotes changeNotes) {
+    return new CanSeeChangePredicate(
+        args.db, args.permissionBackend, args.userFactory, changeNotes);
+  }
+
+  static class AccountPredicate extends IndexPredicate<AccountState>
+      implements Matchable<AccountState> {
     AccountPredicate(FieldDef<AccountState, ?> def, String value) {
       super(def, value);
     }
@@ -129,6 +139,16 @@
     AccountPredicate(FieldDef<AccountState, ?> def, String name, String value) {
       super(def, name, value);
     }
+
+    @Override
+    public boolean match(AccountState object) throws OrmException {
+      return true;
+    }
+
+    @Override
+    public int getCost() {
+      return 1;
+    }
   }
 
   private AccountPredicates() {}
diff --git a/java/com/google/gerrit/server/query/account/AccountQueryBuilder.java b/java/com/google/gerrit/server/query/account/AccountQueryBuilder.java
index 8f6ec8b..8b6e1e4 100644
--- a/java/com/google/gerrit/server/query/account/AccountQueryBuilder.java
+++ b/java/com/google/gerrit/server/query/account/AccountQueryBuilder.java
@@ -25,14 +25,19 @@
 import com.google.gerrit.index.query.QueryBuilder;
 import com.google.gerrit.index.query.QueryParseException;
 import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.ChangeFinder;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.AccountState;
 import com.google.gerrit.server.index.account.AccountField;
 import com.google.gerrit.server.index.account.AccountIndexCollection;
+import com.google.gerrit.server.notedb.ChangeNotes;
+import com.google.gerrit.server.permissions.ChangePermission;
 import com.google.gerrit.server.permissions.GlobalPermission;
 import com.google.gerrit.server.permissions.PermissionBackend;
 import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.ProvisionException;
@@ -56,17 +61,27 @@
       new QueryBuilder.Definition<>(AccountQueryBuilder.class);
 
   public static class Arguments {
+    final Provider<ReviewDb> db;
+    final ChangeFinder changeFinder;
+    final IdentifiedUser.GenericFactory userFactory;
+    final PermissionBackend permissionBackend;
+
     private final Provider<CurrentUser> self;
     private final AccountIndexCollection indexes;
-    private final PermissionBackend permissionBackend;
 
     @Inject
     public Arguments(
         Provider<CurrentUser> self,
         AccountIndexCollection indexes,
+        Provider<ReviewDb> db,
+        ChangeFinder changeFinder,
+        IdentifiedUser.GenericFactory userFactory,
         PermissionBackend permissionBackend) {
       this.self = self;
       this.indexes = indexes;
+      this.db = db;
+      this.changeFinder = changeFinder;
+      this.userFactory = userFactory;
       this.permissionBackend = permissionBackend;
     }
 
@@ -105,6 +120,22 @@
   }
 
   @Operator
+  public Predicate<AccountState> cansee(String change)
+      throws QueryParseException, OrmException, PermissionBackendException {
+    ChangeNotes changeNotes = args.changeFinder.findOne(change);
+    if (changeNotes == null
+        || !args.permissionBackend
+            .user(args.getUser())
+            .database(args.db)
+            .change(changeNotes)
+            .test(ChangePermission.READ)) {
+      throw error(String.format("change %s not found", change));
+    }
+
+    return AccountPredicates.cansee(args, changeNotes);
+  }
+
+  @Operator
   public Predicate<AccountState> email(String email)
       throws PermissionBackendException, QueryParseException {
     if (canSeeSecondaryEmails()) {
@@ -167,6 +198,14 @@
   protected Predicate<AccountState> defaultField(String query) {
     Predicate<AccountState> defaultPredicate =
         AccountPredicates.defaultPredicate(args.schema(), checkedCanSeeSecondaryEmails(), query);
+    if (query.startsWith("cansee:")) {
+      try {
+        return cansee(query.substring(7));
+      } catch (OrmException | QueryParseException | PermissionBackendException e) {
+        // Ignore, fall back to default query
+      }
+    }
+
     if ("self".equalsIgnoreCase(query) || "me".equalsIgnoreCase(query)) {
       try {
         return Predicate.or(defaultPredicate, AccountPredicates.id(self()));
diff --git a/java/com/google/gerrit/server/query/account/CanSeeChangePredicate.java b/java/com/google/gerrit/server/query/account/CanSeeChangePredicate.java
new file mode 100644
index 0000000..c436a45
--- /dev/null
+++ b/java/com/google/gerrit/server/query/account/CanSeeChangePredicate.java
@@ -0,0 +1,85 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.query.account;
+
+import com.google.gerrit.index.query.PostFilterPredicate;
+import com.google.gerrit.index.query.Predicate;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.account.AccountState;
+import com.google.gerrit.server.notedb.ChangeNotes;
+import com.google.gerrit.server.permissions.ChangePermission;
+import com.google.gerrit.server.permissions.PermissionBackend;
+import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Provider;
+import java.util.Collection;
+import java.util.Objects;
+
+public class CanSeeChangePredicate extends PostFilterPredicate<AccountState> {
+  private final Provider<ReviewDb> db;
+  private final PermissionBackend permissionBackend;
+  private final IdentifiedUser.GenericFactory userFactory;
+  private final ChangeNotes changeNotes;
+
+  CanSeeChangePredicate(
+      Provider<ReviewDb> db,
+      PermissionBackend permissionBackend,
+      IdentifiedUser.GenericFactory userFactory,
+      ChangeNotes changeNotes) {
+    this.db = db;
+    this.permissionBackend = permissionBackend;
+    this.userFactory = userFactory;
+    this.changeNotes = changeNotes;
+  }
+
+  @Override
+  public boolean match(AccountState accountState) throws OrmException {
+    try {
+      return permissionBackend
+          .user(userFactory.create(accountState.getAccount().getId()))
+          .database(db)
+          .change(changeNotes)
+          .test(ChangePermission.READ);
+    } catch (PermissionBackendException e) {
+      throw new OrmException("Failed to check if account can see change", e);
+    }
+  }
+
+  @Override
+  public int getCost() {
+    return 1;
+  }
+
+  @Override
+  public Predicate<AccountState> copy(Collection<? extends Predicate<AccountState>> children) {
+    return new CanSeeChangePredicate(db, permissionBackend, userFactory, changeNotes);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(changeNotes.getChange().getChangeId());
+  }
+
+  @Override
+  public boolean equals(Object other) {
+    if (other == null) {
+      return false;
+    }
+    return getClass() == other.getClass()
+        && changeNotes.getChange().getChangeId()
+            == ((CanSeeChangePredicate) other).changeNotes.getChange().getChangeId();
+  }
+}
diff --git a/java/com/google/gerrit/server/query/project/ProjectIsVisibleToPredicate.java b/java/com/google/gerrit/server/query/project/ProjectIsVisibleToPredicate.java
index 20032ce..24209c7 100644
--- a/java/com/google/gerrit/server/query/project/ProjectIsVisibleToPredicate.java
+++ b/java/com/google/gerrit/server/query/project/ProjectIsVisibleToPredicate.java
@@ -14,12 +14,12 @@
 
 package com.google.gerrit.server.query.project;
 
+import com.google.gerrit.index.project.ProjectData;
 import com.google.gerrit.index.query.IsVisibleToPredicate;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.index.IndexUtils;
 import com.google.gerrit.server.permissions.PermissionBackend;
 import com.google.gerrit.server.permissions.ProjectPermission;
-import com.google.gerrit.server.project.ProjectData;
 import com.google.gerrit.server.query.account.AccountQueryBuilder;
 import com.google.gwtorm.server.OrmException;
 
@@ -35,6 +35,10 @@
 
   @Override
   public boolean match(ProjectData pd) throws OrmException {
+    if (!pd.getProject().getState().permitsRead()) {
+      return false;
+    }
+
     return permissionBackend
         .user(user)
         .project(pd.getProject().getNameKey())
diff --git a/java/com/google/gerrit/server/query/project/ProjectPredicates.java b/java/com/google/gerrit/server/query/project/ProjectPredicates.java
index 379c564..b4f56d4 100644
--- a/java/com/google/gerrit/server/query/project/ProjectPredicates.java
+++ b/java/com/google/gerrit/server/query/project/ProjectPredicates.java
@@ -14,12 +14,11 @@
 
 package com.google.gerrit.server.query.project;
 
-import com.google.gerrit.index.FieldDef;
-import com.google.gerrit.index.query.IndexPredicate;
+import com.google.gerrit.index.project.ProjectData;
+import com.google.gerrit.index.project.ProjectField;
+import com.google.gerrit.index.project.ProjectPredicate;
 import com.google.gerrit.index.query.Predicate;
 import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.server.index.project.ProjectField;
-import com.google.gerrit.server.project.ProjectData;
 import java.util.Locale;
 
 public class ProjectPredicates {
@@ -35,11 +34,5 @@
     return new ProjectPredicate(ProjectField.DESCRIPTION, description);
   }
 
-  static class ProjectPredicate extends IndexPredicate<ProjectData> {
-    ProjectPredicate(FieldDef<ProjectData, ?> def, String value) {
-      super(def, value);
-    }
-  }
-
   private ProjectPredicates() {}
 }
diff --git a/java/com/google/gerrit/server/query/project/ProjectQueryBuilder.java b/java/com/google/gerrit/server/query/project/ProjectQueryBuilder.java
index e9e9c0f..be7ea22 100644
--- a/java/com/google/gerrit/server/query/project/ProjectQueryBuilder.java
+++ b/java/com/google/gerrit/server/query/project/ProjectQueryBuilder.java
@@ -17,12 +17,12 @@
 import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
 import com.google.common.primitives.Ints;
+import com.google.gerrit.index.project.ProjectData;
 import com.google.gerrit.index.query.LimitPredicate;
 import com.google.gerrit.index.query.Predicate;
 import com.google.gerrit.index.query.QueryBuilder;
 import com.google.gerrit.index.query.QueryParseException;
 import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.server.project.ProjectData;
 import com.google.inject.Inject;
 import java.util.List;
 
diff --git a/java/com/google/gerrit/server/query/project/ProjectQueryProcessor.java b/java/com/google/gerrit/server/query/project/ProjectQueryProcessor.java
index 1e181e5..79b7943 100644
--- a/java/com/google/gerrit/server/query/project/ProjectQueryProcessor.java
+++ b/java/com/google/gerrit/server/query/project/ProjectQueryProcessor.java
@@ -18,6 +18,10 @@
 import static com.google.gerrit.server.query.project.ProjectQueryBuilder.FIELD_LIMIT;
 
 import com.google.gerrit.index.IndexConfig;
+import com.google.gerrit.index.project.ProjectData;
+import com.google.gerrit.index.project.ProjectIndexCollection;
+import com.google.gerrit.index.project.ProjectIndexRewriter;
+import com.google.gerrit.index.project.ProjectSchemaDefinitions;
 import com.google.gerrit.index.query.AndSource;
 import com.google.gerrit.index.query.IndexPredicate;
 import com.google.gerrit.index.query.Predicate;
@@ -25,11 +29,7 @@
 import com.google.gerrit.metrics.MetricMaker;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.account.AccountLimits;
-import com.google.gerrit.server.index.project.ProjectIndexCollection;
-import com.google.gerrit.server.index.project.ProjectIndexRewriter;
-import com.google.gerrit.server.index.project.ProjectSchemaDefinitions;
 import com.google.gerrit.server.permissions.PermissionBackend;
-import com.google.gerrit.server.project.ProjectData;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
diff --git a/java/com/google/gerrit/server/restapi/BUILD b/java/com/google/gerrit/server/restapi/BUILD
index 5b9800b..a307d43 100644
--- a/java/com/google/gerrit/server/restapi/BUILD
+++ b/java/com/google/gerrit/server/restapi/BUILD
@@ -11,6 +11,7 @@
         "//java/com/google/gerrit/extensions:api",
         "//java/com/google/gerrit/index",
         "//java/com/google/gerrit/index:query_exception",
+        "//java/com/google/gerrit/index/project",
         "//java/com/google/gerrit/metrics",
         "//java/com/google/gerrit/prettify:server",
         "//java/com/google/gerrit/reviewdb:server",
diff --git a/java/com/google/gerrit/server/restapi/access/AccessCollection.java b/java/com/google/gerrit/server/restapi/access/AccessCollection.java
index 4e12291..d4528c5 100644
--- a/java/com/google/gerrit/server/restapi/access/AccessCollection.java
+++ b/java/com/google/gerrit/server/restapi/access/AccessCollection.java
@@ -20,7 +20,6 @@
 import com.google.gerrit.extensions.restapi.RestCollection;
 import com.google.gerrit.extensions.restapi.RestView;
 import com.google.gerrit.extensions.restapi.TopLevelResource;
-import com.google.gerrit.server.access.AccessResource;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
diff --git a/java/com/google/gerrit/server/access/AccessResource.java b/java/com/google/gerrit/server/restapi/access/AccessResource.java
similarity index 94%
rename from java/com/google/gerrit/server/access/AccessResource.java
rename to java/com/google/gerrit/server/restapi/access/AccessResource.java
index a1fe0c9..915165b 100644
--- a/java/com/google/gerrit/server/access/AccessResource.java
+++ b/java/com/google/gerrit/server/restapi/access/AccessResource.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.access;
+package com.google.gerrit.server.restapi.access;
 
 import com.google.gerrit.extensions.restapi.RestResource;
 import com.google.gerrit.extensions.restapi.RestView;
diff --git a/java/com/google/gerrit/server/restapi/access/Module.java b/java/com/google/gerrit/server/restapi/access/Module.java
index 21357fa..7da2e26b 100644
--- a/java/com/google/gerrit/server/restapi/access/Module.java
+++ b/java/com/google/gerrit/server/restapi/access/Module.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.restapi.access;
 
-import static com.google.gerrit.server.access.AccessResource.ACCESS_KIND;
+import static com.google.gerrit.server.restapi.access.AccessResource.ACCESS_KIND;
 
 import com.google.gerrit.extensions.registration.DynamicMap;
 import com.google.gerrit.extensions.restapi.RestApiModule;
diff --git a/java/com/google/gerrit/server/restapi/account/GetGroups.java b/java/com/google/gerrit/server/restapi/account/GetGroups.java
index 992a85a..486a151 100644
--- a/java/com/google/gerrit/server/restapi/account/GetGroups.java
+++ b/java/com/google/gerrit/server/restapi/account/GetGroups.java
@@ -28,6 +28,7 @@
 import com.google.inject.Singleton;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 
 @Singleton
 public class GetGroups implements RestReadView<AccountResource> {
@@ -44,8 +45,9 @@
   public List<GroupInfo> apply(AccountResource resource) throws OrmException {
     IdentifiedUser user = resource.getUser();
     Account.Id userId = user.getAccountId();
-    List<GroupInfo> groups = new ArrayList<>();
-    for (AccountGroup.UUID uuid : user.getEffectiveGroups().getKnownGroups()) {
+    Set<AccountGroup.UUID> knownGroups = user.getEffectiveGroups().getKnownGroups();
+    List<GroupInfo> visibleGroups = new ArrayList<>();
+    for (AccountGroup.UUID uuid : knownGroups) {
       GroupControl ctl;
       try {
         ctl = groupControlFactory.controlFor(uuid);
@@ -53,9 +55,9 @@
         continue;
       }
       if (ctl.isVisible() && ctl.canSeeMember(userId)) {
-        groups.add(json.format(ctl.getGroup()));
+        visibleGroups.add(json.format(ctl.getGroup()));
       }
     }
-    return groups;
+    return visibleGroups;
   }
 }
diff --git a/java/com/google/gerrit/server/restapi/account/Index.java b/java/com/google/gerrit/server/restapi/account/Index.java
index 20a381a..fc6b7b3 100644
--- a/java/com/google/gerrit/server/restapi/account/Index.java
+++ b/java/com/google/gerrit/server/restapi/account/Index.java
@@ -19,8 +19,8 @@
 import com.google.gerrit.extensions.restapi.Response;
 import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.server.CurrentUser;
-import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.account.AccountResource;
+import com.google.gerrit.server.index.account.AccountIndexer;
 import com.google.gerrit.server.permissions.GlobalPermission;
 import com.google.gerrit.server.permissions.PermissionBackend;
 import com.google.gerrit.server.permissions.PermissionBackendException;
@@ -32,14 +32,16 @@
 @Singleton
 public class Index implements RestModifyView<AccountResource, Input> {
 
-  private final AccountCache accountCache;
+  private final Provider<AccountIndexer> accountIndexer;
   private final PermissionBackend permissionBackend;
   private final Provider<CurrentUser> self;
 
   @Inject
   Index(
-      AccountCache accountCache, PermissionBackend permissionBackend, Provider<CurrentUser> self) {
-    this.accountCache = accountCache;
+      Provider<AccountIndexer> accountIndexer,
+      PermissionBackend permissionBackend,
+      Provider<CurrentUser> self) {
+    this.accountIndexer = accountIndexer;
     this.permissionBackend = permissionBackend;
     this.self = self;
   }
@@ -51,8 +53,7 @@
       permissionBackend.user(self).check(GlobalPermission.MODIFY_ACCOUNT);
     }
 
-    // evicting the account from the cache, reindexes the account
-    accountCache.evict(rsrc.getUser().getAccountId());
+    accountIndexer.get().index(rsrc.getUser().getAccountId());
     return Response.none();
   }
 }
diff --git a/java/com/google/gerrit/server/restapi/change/CreateDraftComment.java b/java/com/google/gerrit/server/restapi/change/CreateDraftComment.java
index afcc8f7..be689ca 100644
--- a/java/com/google/gerrit/server/restapi/change/CreateDraftComment.java
+++ b/java/com/google/gerrit/server/restapi/change/CreateDraftComment.java
@@ -34,6 +34,7 @@
 import com.google.gerrit.server.PatchSetUtil;
 import com.google.gerrit.server.change.RevisionResource;
 import com.google.gerrit.server.patch.PatchListCache;
+import com.google.gerrit.server.patch.PatchListNotAvailableException;
 import com.google.gerrit.server.update.BatchUpdate;
 import com.google.gerrit.server.update.BatchUpdateOp;
 import com.google.gerrit.server.update.ChangeContext;
@@ -108,7 +109,8 @@
 
     @Override
     public boolean updateChange(ChangeContext ctx)
-        throws ResourceNotFoundException, OrmException, UnprocessableEntityException {
+        throws ResourceNotFoundException, OrmException, UnprocessableEntityException,
+            PatchListNotAvailableException {
       PatchSet ps = psUtil.get(ctx.getDb(), ctx.getNotes(), psId);
       if (ps == null) {
         throw new ResourceNotFoundException("patch set not found: " + psId);
diff --git a/java/com/google/gerrit/server/restapi/change/DeleteDraftComment.java b/java/com/google/gerrit/server/restapi/change/DeleteDraftComment.java
index ee57c20..e81f9f1 100644
--- a/java/com/google/gerrit/server/restapi/change/DeleteDraftComment.java
+++ b/java/com/google/gerrit/server/restapi/change/DeleteDraftComment.java
@@ -29,6 +29,7 @@
 import com.google.gerrit.server.PatchSetUtil;
 import com.google.gerrit.server.change.DraftCommentResource;
 import com.google.gerrit.server.patch.PatchListCache;
+import com.google.gerrit.server.patch.PatchListNotAvailableException;
 import com.google.gerrit.server.update.BatchUpdate;
 import com.google.gerrit.server.update.BatchUpdateOp;
 import com.google.gerrit.server.update.ChangeContext;
@@ -87,7 +88,8 @@
     }
 
     @Override
-    public boolean updateChange(ChangeContext ctx) throws ResourceNotFoundException, OrmException {
+    public boolean updateChange(ChangeContext ctx)
+        throws ResourceNotFoundException, OrmException, PatchListNotAvailableException {
       Optional<Comment> maybeComment =
           commentsUtil.getDraft(ctx.getDb(), ctx.getNotes(), ctx.getIdentifiedUser(), key);
       if (!maybeComment.isPresent()) {
diff --git a/java/com/google/gerrit/server/restapi/change/PostReview.java b/java/com/google/gerrit/server/restapi/change/PostReview.java
index 8e78ec0..5ea72c0 100644
--- a/java/com/google/gerrit/server/restapi/change/PostReview.java
+++ b/java/com/google/gerrit/server/restapi/change/PostReview.java
@@ -839,7 +839,8 @@
 
     @Override
     public boolean updateChange(ChangeContext ctx)
-        throws OrmException, ResourceConflictException, UnprocessableEntityException, IOException {
+        throws OrmException, ResourceConflictException, UnprocessableEntityException, IOException,
+            PatchListNotAvailableException {
       user = ctx.getIdentifiedUser();
       notes = ctx.getNotes();
       ps = psUtil.get(ctx.getDb(), ctx.getNotes(), psId);
@@ -881,7 +882,7 @@
     }
 
     private boolean insertComments(ChangeContext ctx)
-        throws OrmException, UnprocessableEntityException {
+        throws OrmException, UnprocessableEntityException, PatchListNotAvailableException {
       Map<String, List<CommentInput>> map = in.comments;
       if (map == null) {
         map = Collections.emptyMap();
@@ -941,7 +942,8 @@
       return !toPublish.isEmpty();
     }
 
-    private boolean insertRobotComments(ChangeContext ctx) throws OrmException {
+    private boolean insertRobotComments(ChangeContext ctx)
+        throws OrmException, PatchListNotAvailableException {
       if (in.robotComments == null) {
         return false;
       }
@@ -952,7 +954,8 @@
       return !newRobotComments.isEmpty();
     }
 
-    private List<RobotComment> getNewRobotComments(ChangeContext ctx) throws OrmException {
+    private List<RobotComment> getNewRobotComments(ChangeContext ctx)
+        throws OrmException, PatchListNotAvailableException {
       List<RobotComment> toAdd = new ArrayList<>(in.robotComments.size());
 
       Set<CommentSetEntry> existingIds =
@@ -972,7 +975,8 @@
     }
 
     private RobotComment createRobotCommentFromInput(
-        ChangeContext ctx, String path, RobotCommentInput robotCommentInput) throws OrmException {
+        ChangeContext ctx, String path, RobotCommentInput robotCommentInput)
+        throws PatchListNotAvailableException {
       RobotComment robotComment =
           commentsUtil.newRobotComment(
               ctx,
diff --git a/java/com/google/gerrit/server/restapi/change/PostReviewers.java b/java/com/google/gerrit/server/restapi/change/PostReviewers.java
index 4ff3862..f9d7083 100644
--- a/java/com/google/gerrit/server/restapi/change/PostReviewers.java
+++ b/java/com/google/gerrit/server/restapi/change/PostReviewers.java
@@ -194,13 +194,20 @@
 
     Addition byAccountId =
         addByAccountId(reviewer, rsrc, state, notify, accountsToNotify, allowGroup, allowByEmail);
+
+    Addition wholeGroup = null;
+    if (byAccountId == null || !byAccountId.exactMatchFound) {
+      wholeGroup =
+          addWholeGroup(
+              reviewer, rsrc, state, notify, accountsToNotify, confirmed, allowGroup, allowByEmail);
+      if (wholeGroup != null && wholeGroup.exactMatchFound) {
+        return wholeGroup;
+      }
+    }
+
     if (byAccountId != null) {
       return byAccountId;
     }
-
-    Addition wholeGroup =
-        addWholeGroup(
-            reviewer, rsrc, state, notify, accountsToNotify, confirmed, allowGroup, allowByEmail);
     if (wholeGroup != null) {
       return wholeGroup;
     }
@@ -216,7 +223,8 @@
         null,
         CC,
         NotifyHandling.NONE,
-        ImmutableListMultimap.of());
+        ImmutableListMultimap.of(),
+        true);
   }
 
   @Nullable
@@ -229,9 +237,14 @@
       boolean allowGroup,
       boolean allowByEmail)
       throws OrmException, PermissionBackendException, IOException, ConfigInvalidException {
-    Account.Id accountId = null;
+    IdentifiedUser user = null;
+    boolean exactMatchFound = false;
     try {
-      accountId = accounts.parse(reviewer).getAccountId();
+      user = accounts.parse(reviewer);
+      if (reviewer.equalsIgnoreCase(user.getName())
+          || reviewer.equals(String.valueOf(user.getAccountId()))) {
+        exactMatchFound = true;
+      }
     } catch (UnprocessableEntityException | AuthException e) {
       // AuthException won't occur since the user is authenticated at this point.
       if (!allowGroup && !allowByEmail) {
@@ -242,13 +255,20 @@
       return null;
     }
 
-    ReviewerResource rrsrc = reviewerFactory.create(rsrc, accountId);
+    ReviewerResource rrsrc = reviewerFactory.create(rsrc, user.getAccountId());
     Account member = rrsrc.getReviewerUser().getAccount();
     PermissionBackend.ForRef perm =
         permissionBackend.user(rrsrc.getReviewerUser()).ref(rrsrc.getChange().getDest());
     if (isValidReviewer(member, perm)) {
       return new Addition(
-          reviewer, rsrc, ImmutableSet.of(member.getId()), null, state, notify, accountsToNotify);
+          reviewer,
+          rsrc,
+          ImmutableSet.of(member.getId()),
+          null,
+          state,
+          notify,
+          accountsToNotify,
+          exactMatchFound);
     }
     if (!member.isActive()) {
       if (allowByEmail && state == CC) {
@@ -328,7 +348,7 @@
       }
     }
 
-    return new Addition(reviewer, rsrc, reviewers, null, state, notify, accountsToNotify);
+    return new Addition(reviewer, rsrc, reviewers, null, state, notify, accountsToNotify, true);
   }
 
   @Nullable
@@ -357,7 +377,7 @@
       return fail(reviewer, MessageFormat.format(ChangeMessages.get().reviewerInvalid, reviewer));
     }
     return new Addition(
-        reviewer, rsrc, null, ImmutableList.of(adr), state, notify, accountsToNotify);
+        reviewer, rsrc, null, ImmutableList.of(adr), state, notify, accountsToNotify, true);
   }
 
   private boolean isValidReviewer(Account member, PermissionBackend.ForRef perm)
@@ -395,6 +415,7 @@
     final ReviewerState state;
     final ChangeNotes notes;
     final IdentifiedUser caller;
+    final boolean exactMatchFound;
 
     Addition(String reviewer) {
       result = new AddReviewerResult(reviewer);
@@ -404,6 +425,7 @@
       state = REVIEWER;
       notes = null;
       caller = null;
+      exactMatchFound = false;
     }
 
     protected Addition(
@@ -413,7 +435,8 @@
         @Nullable Collection<Address> reviewersByEmail,
         ReviewerState state,
         @Nullable NotifyHandling notify,
-        ListMultimap<RecipientType, Account.Id> accountsToNotify) {
+        ListMultimap<RecipientType, Account.Id> accountsToNotify,
+        boolean exactMatchFound) {
       checkArgument(
           reviewers != null || reviewersByEmail != null,
           "must have either reviewers or reviewersByEmail");
@@ -427,6 +450,7 @@
       op =
           postReviewersOpFactory.create(
               rsrc, this.reviewers, this.reviewersByEmail, state, notify, accountsToNotify);
+      this.exactMatchFound = exactMatchFound;
     }
 
     void gatherResults() throws OrmException, PermissionBackendException {
diff --git a/java/com/google/gerrit/server/restapi/change/PutDraftComment.java b/java/com/google/gerrit/server/restapi/change/PutDraftComment.java
index 3017d89..e6ede34 100644
--- a/java/com/google/gerrit/server/restapi/change/PutDraftComment.java
+++ b/java/com/google/gerrit/server/restapi/change/PutDraftComment.java
@@ -33,6 +33,7 @@
 import com.google.gerrit.server.change.DraftCommentResource;
 import com.google.gerrit.server.notedb.ChangeUpdate;
 import com.google.gerrit.server.patch.PatchListCache;
+import com.google.gerrit.server.patch.PatchListNotAvailableException;
 import com.google.gerrit.server.update.BatchUpdate;
 import com.google.gerrit.server.update.BatchUpdateOp;
 import com.google.gerrit.server.update.ChangeContext;
@@ -113,7 +114,8 @@
     }
 
     @Override
-    public boolean updateChange(ChangeContext ctx) throws ResourceNotFoundException, OrmException {
+    public boolean updateChange(ChangeContext ctx)
+        throws ResourceNotFoundException, OrmException, PatchListNotAvailableException {
       Optional<Comment> maybeComment =
           commentsUtil.getDraft(ctx.getDb(), ctx.getNotes(), ctx.getIdentifiedUser(), key);
       if (!maybeComment.isPresent()) {
diff --git a/java/com/google/gerrit/server/restapi/change/Revert.java b/java/com/google/gerrit/server/restapi/change/Revert.java
index b55ca5e..4545794 100644
--- a/java/com/google/gerrit/server/restapi/change/Revert.java
+++ b/java/com/google/gerrit/server/restapi/change/Revert.java
@@ -18,7 +18,10 @@
 import static com.google.gerrit.server.permissions.RefPermission.CREATE_CHANGE;
 
 import com.google.common.base.Strings;
+import com.google.common.collect.ListMultimap;
 import com.google.gerrit.common.TimeUtil;
+import com.google.gerrit.extensions.api.changes.NotifyHandling;
+import com.google.gerrit.extensions.api.changes.RecipientType;
 import com.google.gerrit.extensions.api.changes.RevertInput;
 import com.google.gerrit.extensions.common.ChangeInfo;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
@@ -43,6 +46,7 @@
 import com.google.gerrit.server.change.ChangeJson;
 import com.google.gerrit.server.change.ChangeMessages;
 import com.google.gerrit.server.change.ChangeResource;
+import com.google.gerrit.server.change.NotifyUtil;
 import com.google.gerrit.server.extensions.events.ChangeReverted;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.mail.send.RevertedSender;
@@ -70,6 +74,7 @@
 import java.text.MessageFormat;
 import java.util.HashSet;
 import java.util.Set;
+import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
 import org.eclipse.jgit.lib.CommitBuilder;
 import org.eclipse.jgit.lib.ObjectId;
@@ -102,6 +107,7 @@
   private final ChangeReverted changeReverted;
   private final ContributorAgreementsChecker contributorAgreements;
   private final ProjectCache projectCache;
+  private final NotifyUtil notifyUtil;
 
   @Inject
   Revert(
@@ -119,7 +125,8 @@
       ApprovalsUtil approvalsUtil,
       ChangeReverted changeReverted,
       ContributorAgreementsChecker contributorAgreements,
-      ProjectCache projectCache) {
+      ProjectCache projectCache,
+      NotifyUtil notifyUtil) {
     super(retryHelper);
     this.db = db;
     this.permissionBackend = permissionBackend;
@@ -135,13 +142,14 @@
     this.changeReverted = changeReverted;
     this.contributorAgreements = contributorAgreements;
     this.projectCache = projectCache;
+    this.notifyUtil = notifyUtil;
   }
 
   @Override
   public ChangeInfo applyImpl(
       BatchUpdate.Factory updateFactory, ChangeResource rsrc, RevertInput input)
       throws IOException, OrmException, RestApiException, UpdateException, NoSuchChangeException,
-          PermissionBackendException, NoSuchProjectException {
+          PermissionBackendException, NoSuchProjectException, ConfigInvalidException {
     Change change = rsrc.getChange();
     if (change.getStatus() != Change.Status.MERGED) {
       throw new ResourceConflictException("change is " + ChangeUtil.status(change));
@@ -151,14 +159,14 @@
     permissionBackend.user(rsrc.getUser()).ref(change.getDest()).check(CREATE_CHANGE);
     projectCache.checkedGet(rsrc.getProject()).checkStatePermitsWrite();
 
-    Change.Id revertId =
-        revert(updateFactory, rsrc.getNotes(), rsrc.getUser(), Strings.emptyToNull(input.message));
+    Change.Id revertId = revert(updateFactory, rsrc.getNotes(), rsrc.getUser(), input);
     return json.noOptions().format(rsrc.getProject(), revertId);
   }
 
   private Change.Id revert(
-      BatchUpdate.Factory updateFactory, ChangeNotes notes, CurrentUser user, String message)
-      throws OrmException, IOException, RestApiException, UpdateException {
+      BatchUpdate.Factory updateFactory, ChangeNotes notes, CurrentUser user, RevertInput input)
+      throws OrmException, IOException, RestApiException, UpdateException, ConfigInvalidException {
+    String message = Strings.emptyToNull(input.message);
     Change.Id changeIdToRevert = notes.getChangeId();
     PatchSet.Id patchSetId = notes.getChange().currentPatchSetId();
     PatchSet patch = psUtil.get(db.get(), notes, patchSetId);
@@ -213,11 +221,16 @@
       ObjectId id = oi.insert(revertCommitBuilder);
       RevCommit revertCommit = revWalk.parseCommit(id);
 
+      ListMultimap<RecipientType, Account.Id> accountsToNotify =
+          notifyUtil.resolveAccounts(input.notifyDetails);
+
       ChangeInserter ins =
           changeInserterFactory
               .create(changeId, revertCommit, notes.getChange().getDest().get())
               .setTopic(changeToRevert.getTopic());
       ins.setMessage("Uploaded patch set 1.");
+      ins.setNotify(input.notify);
+      ins.setAccountsToNotify(accountsToNotify);
 
       ReviewerSet reviewerSet = approvalsUtil.getReviewers(db.get(), notes);
 
@@ -235,7 +248,7 @@
       try (BatchUpdate bu = updateFactory.create(db.get(), project, user, now)) {
         bu.setRepository(git, revWalk, oi);
         bu.insertChange(ins);
-        bu.addOp(changeId, new NotifyOp(notes.getChange(), ins));
+        bu.addOp(changeId, new NotifyOp(changeToRevert, ins, input.notify, accountsToNotify));
         bu.addOp(changeToRevert.getId(), new PostRevertedMessageOp(computedChangeId));
         bu.execute();
       }
@@ -269,23 +282,31 @@
   private class NotifyOp implements BatchUpdateOp {
     private final Change change;
     private final ChangeInserter ins;
+    private final NotifyHandling notifyHandling;
+    private final ListMultimap<RecipientType, Account.Id> accountsToNotify;
 
-    NotifyOp(Change change, ChangeInserter ins) {
+    NotifyOp(
+        Change change,
+        ChangeInserter ins,
+        NotifyHandling notifyHandling,
+        ListMultimap<RecipientType, Account.Id> accountsToNotify) {
       this.change = change;
       this.ins = ins;
+      this.notifyHandling = notifyHandling;
+      this.accountsToNotify = accountsToNotify;
     }
 
     @Override
     public void postUpdate(Context ctx) throws Exception {
       changeReverted.fire(change, ins.getChange(), ctx.getWhen());
-      Change.Id changeId = ins.getChange().getId();
       try {
-        RevertedSender cm = revertedSenderFactory.create(ctx.getProject(), changeId);
+        RevertedSender cm = revertedSenderFactory.create(ctx.getProject(), change.getId());
         cm.setFrom(ctx.getAccountId());
-        cm.setChangeMessage(ins.getChangeMessage().getMessage(), ctx.getWhen());
+        cm.setNotify(notifyHandling);
+        cm.setAccountsToNotify(accountsToNotify);
         cm.send();
       } catch (Exception err) {
-        log.error("Cannot send email for revert change " + changeId, err);
+        log.error("Cannot send email for revert change " + change.getId(), err);
       }
     }
   }
diff --git a/java/com/google/gerrit/server/restapi/change/SetReadyForReview.java b/java/com/google/gerrit/server/restapi/change/SetReadyForReview.java
index e701bb0..f487c28 100644
--- a/java/com/google/gerrit/server/restapi/change/SetReadyForReview.java
+++ b/java/com/google/gerrit/server/restapi/change/SetReadyForReview.java
@@ -24,9 +24,13 @@
 import com.google.gerrit.reviewdb.client.Change.Status;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.ChangeUtil;
+import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.change.ChangeResource;
 import com.google.gerrit.server.change.WorkInProgressOp;
 import com.google.gerrit.server.change.WorkInProgressOp.Input;
+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.update.BatchUpdate;
 import com.google.gerrit.server.update.RetryHelper;
 import com.google.gerrit.server.update.RetryingRestModifyView;
@@ -40,21 +44,30 @@
     implements UiAction<ChangeResource> {
   private final WorkInProgressOp.Factory opFactory;
   private final Provider<ReviewDb> db;
+  private final Provider<CurrentUser> self;
+  private final PermissionBackend permissionBackend;
 
   @Inject
   SetReadyForReview(
-      RetryHelper retryHelper, WorkInProgressOp.Factory opFactory, Provider<ReviewDb> db) {
+      RetryHelper retryHelper,
+      WorkInProgressOp.Factory opFactory,
+      Provider<ReviewDb> db,
+      Provider<CurrentUser> self,
+      PermissionBackend permissionBackend) {
     super(retryHelper);
     this.opFactory = opFactory;
     this.db = db;
+    this.self = self;
+    this.permissionBackend = permissionBackend;
   }
 
   @Override
   protected Response<?> applyImpl(
       BatchUpdate.Factory updateFactory, ChangeResource rsrc, Input input)
-      throws RestApiException, UpdateException {
+      throws RestApiException, UpdateException, PermissionBackendException {
     Change change = rsrc.getChange();
-    if (!rsrc.isUserOwner()) {
+    if (!rsrc.isUserOwner()
+        && !permissionBackend.user(self).test(GlobalPermission.ADMINISTRATE_SERVER)) {
       throw new AuthException("not allowed to set ready for review");
     }
 
diff --git a/java/com/google/gerrit/server/restapi/change/SetWorkInProgress.java b/java/com/google/gerrit/server/restapi/change/SetWorkInProgress.java
index 9f82433..7fcf6a0 100644
--- a/java/com/google/gerrit/server/restapi/change/SetWorkInProgress.java
+++ b/java/com/google/gerrit/server/restapi/change/SetWorkInProgress.java
@@ -24,9 +24,13 @@
 import com.google.gerrit.reviewdb.client.Change.Status;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.ChangeUtil;
+import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.change.ChangeResource;
 import com.google.gerrit.server.change.WorkInProgressOp;
 import com.google.gerrit.server.change.WorkInProgressOp.Input;
+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.update.BatchUpdate;
 import com.google.gerrit.server.update.RetryHelper;
 import com.google.gerrit.server.update.RetryingRestModifyView;
@@ -40,21 +44,31 @@
     implements UiAction<ChangeResource> {
   private final WorkInProgressOp.Factory opFactory;
   private final Provider<ReviewDb> db;
+  private final Provider<CurrentUser> self;
+  private final PermissionBackend permissionBackend;
 
   @Inject
   SetWorkInProgress(
-      WorkInProgressOp.Factory opFactory, RetryHelper retryHelper, Provider<ReviewDb> db) {
+      WorkInProgressOp.Factory opFactory,
+      RetryHelper retryHelper,
+      Provider<ReviewDb> db,
+      Provider<CurrentUser> self,
+      PermissionBackend permissionBackend) {
     super(retryHelper);
     this.opFactory = opFactory;
     this.db = db;
+    this.self = self;
+    this.permissionBackend = permissionBackend;
   }
 
   @Override
   protected Response<?> applyImpl(
       BatchUpdate.Factory updateFactory, ChangeResource rsrc, Input input)
-      throws RestApiException, UpdateException {
+      throws RestApiException, UpdateException, PermissionBackendException {
     Change change = rsrc.getChange();
-    if (!rsrc.isUserOwner()) {
+
+    if (!rsrc.isUserOwner()
+        && !permissionBackend.user(self).test(GlobalPermission.ADMINISTRATE_SERVER)) {
       throw new AuthException("not allowed to set work in progress");
     }
 
diff --git a/java/com/google/gerrit/server/restapi/config/SetDiffPreferences.java b/java/com/google/gerrit/server/restapi/config/SetDiffPreferences.java
index 1f6feb4..2aa3fb9 100644
--- a/java/com/google/gerrit/server/restapi/config/SetDiffPreferences.java
+++ b/java/com/google/gerrit/server/restapi/config/SetDiffPreferences.java
@@ -66,7 +66,7 @@
 
     try (MetaDataUpdate md = metaDataUpdateFactory.get().create(allUsersName)) {
       DiffPreferencesInfo updatedPrefs = Preferences.updateDefaultDiffPreferences(md, input);
-      accountCache.evictAllNoReindex();
+      accountCache.evictAll();
       return updatedPrefs;
     }
   }
diff --git a/java/com/google/gerrit/server/restapi/config/SetEditPreferences.java b/java/com/google/gerrit/server/restapi/config/SetEditPreferences.java
index a531152..36bcdb3 100644
--- a/java/com/google/gerrit/server/restapi/config/SetEditPreferences.java
+++ b/java/com/google/gerrit/server/restapi/config/SetEditPreferences.java
@@ -66,7 +66,7 @@
 
     try (MetaDataUpdate md = metaDataUpdateFactory.get().create(allUsersName)) {
       EditPreferencesInfo updatedPrefs = Preferences.updateDefaultEditPreferences(md, input);
-      accountCache.evictAllNoReindex();
+      accountCache.evictAll();
       return updatedPrefs;
     }
   }
diff --git a/java/com/google/gerrit/server/restapi/config/SetPreferences.java b/java/com/google/gerrit/server/restapi/config/SetPreferences.java
index f3ba8f9..0815af7 100644
--- a/java/com/google/gerrit/server/restapi/config/SetPreferences.java
+++ b/java/com/google/gerrit/server/restapi/config/SetPreferences.java
@@ -63,7 +63,7 @@
     Preferences.validateMy(input.my);
     try (MetaDataUpdate md = metaDataUpdateFactory.get().create(allUsersName)) {
       GeneralPreferencesInfo updatedPrefs = Preferences.updateDefaultGeneralPreferences(md, input);
-      accountCache.evictAllNoReindex();
+      accountCache.evictAll();
       return updatedPrefs;
     }
   }
diff --git a/java/com/google/gerrit/server/restapi/group/GetAuditLog.java b/java/com/google/gerrit/server/restapi/group/GetAuditLog.java
index 2c583c6..51fffbb 100644
--- a/java/com/google/gerrit/server/restapi/group/GetAuditLog.java
+++ b/java/com/google/gerrit/server/restapi/group/GetAuditLog.java
@@ -117,10 +117,12 @@
         if (includedGroup.isPresent()) {
           member = groupJson.format(new InternalGroupDescription(includedGroup.get()));
         } else {
-          GroupDescription.Basic groupDescription = groupBackend.get(includedGroupUUID);
           member = new GroupInfo();
           member.id = Url.encode(includedGroupUUID.get());
-          member.name = groupDescription.getName();
+          GroupDescription.Basic groupDescription = groupBackend.get(includedGroupUUID);
+          if (groupDescription != null) {
+            member.name = groupDescription.getName();
+          }
         }
 
         auditEvents.add(
diff --git a/java/com/google/gerrit/server/restapi/group/Module.java b/java/com/google/gerrit/server/restapi/group/Module.java
index 7410ee2..fa1e5c7 100644
--- a/java/com/google/gerrit/server/restapi/group/Module.java
+++ b/java/com/google/gerrit/server/restapi/group/Module.java
@@ -60,7 +60,6 @@
     get(GROUP_KIND, "options").to(GetOptions.class);
     put(GROUP_KIND, "options").to(PutOptions.class);
     get(GROUP_KIND, "log.audit").to(GetAuditLog.class);
-    post(GROUP_KIND, "rebuild").to(Rebuild.class);
 
     child(GROUP_KIND, "members").to(MembersCollection.class);
     get(MEMBER_KIND).to(GetMember.class);
diff --git a/java/com/google/gerrit/server/restapi/group/Rebuild.java b/java/com/google/gerrit/server/restapi/group/Rebuild.java
deleted file mode 100644
index 9e8cb3f..0000000
--- a/java/com/google/gerrit/server/restapi/group/Rebuild.java
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.server.restapi.group;
-
-import static com.google.common.base.MoreObjects.firstNonNull;
-import static java.util.stream.Collectors.joining;
-
-import com.google.gerrit.common.data.GlobalCapability;
-import com.google.gerrit.extensions.annotations.RequiresCapability;
-import com.google.gerrit.extensions.restapi.BinaryResult;
-import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
-import com.google.gerrit.extensions.restapi.ResourceConflictException;
-import com.google.gerrit.extensions.restapi.RestApiException;
-import com.google.gerrit.extensions.restapi.RestModifyView;
-import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.reviewdb.client.RefNames;
-import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gerrit.server.config.AllUsersName;
-import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.group.GroupResource;
-import com.google.gerrit.server.group.db.GroupBundle;
-import com.google.gerrit.server.group.db.GroupRebuilder;
-import com.google.gerrit.server.notedb.GroupsMigration;
-import com.google.gerrit.server.restapi.group.Rebuild.Input;
-import com.google.gerrit.server.update.RefUpdateUtil;
-import com.google.gwtorm.server.OrmDuplicateKeyException;
-import com.google.gwtorm.server.OrmException;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import com.google.inject.Singleton;
-import java.io.IOException;
-import java.util.List;
-import org.eclipse.jgit.errors.ConfigInvalidException;
-import org.eclipse.jgit.lib.Repository;
-
-@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
-@Singleton
-public class Rebuild implements RestModifyView<GroupResource, Input> {
-  public static class Input {
-    public Boolean force;
-  }
-
-  private final AllUsersName allUsers;
-  private final GitRepositoryManager repoManager;
-  private final GroupBundle.Factory bundleFactory;
-  private final GroupRebuilder rebuilder;
-  private final GroupsMigration migration;
-  private final Provider<ReviewDb> db;
-
-  @Inject
-  Rebuild(
-      AllUsersName allUsers,
-      GitRepositoryManager repoManager,
-      GroupBundle.Factory bundleFactory,
-      GroupRebuilder rebuilder,
-      GroupsMigration migration,
-      Provider<ReviewDb> db) {
-    this.allUsers = allUsers;
-    this.repoManager = repoManager;
-    this.bundleFactory = bundleFactory;
-    this.rebuilder = rebuilder;
-    this.migration = migration;
-    this.db = db;
-  }
-
-  @Override
-  public BinaryResult apply(GroupResource rsrc, Input input)
-      throws RestApiException, ConfigInvalidException, OrmException, IOException {
-    boolean force = firstNonNull(input.force, false);
-    if (!migration.writeToNoteDb()) {
-      throw new MethodNotAllowedException("NoteDb writes must be enabled");
-    }
-    if (migration.readFromNoteDb() && force) {
-      throw new MethodNotAllowedException("NoteDb reads must not be enabled when force=true");
-    }
-    if (!rsrc.isInternalGroup()) {
-      throw new MethodNotAllowedException("Not an internal group");
-    }
-
-    AccountGroup.UUID uuid = rsrc.getGroup().getGroupUUID();
-    try (Repository repo = repoManager.openRepository(allUsers)) {
-      if (force) {
-        RefUpdateUtil.deleteChecked(repo, RefNames.refsGroups(uuid));
-      }
-      GroupBundle reviewDbBundle =
-          bundleFactory.fromReviewDb(db.get(), rsrc.asInternalGroup().get().getId());
-      try {
-        rebuilder.rebuild(repo, reviewDbBundle, null);
-      } catch (OrmDuplicateKeyException e) {
-        throw new ResourceConflictException("Group already exists in NoteDb");
-      }
-
-      GroupBundle noteDbBundle = bundleFactory.fromNoteDb(repo, uuid);
-
-      List<String> diffs = GroupBundle.compareWithAudits(reviewDbBundle, noteDbBundle);
-      if (diffs.isEmpty()) {
-        return BinaryResult.create("No differences between ReviewDb and NoteDb");
-      }
-      return BinaryResult.create(
-          diffs
-              .stream()
-              .collect(joining("\n", "Differences between ReviewDb and NoteDb:\n", "\n")));
-    }
-  }
-}
diff --git a/java/com/google/gerrit/server/restapi/project/CreateProject.java b/java/com/google/gerrit/server/restapi/project/CreateProject.java
index eb44118..fe26d33 100644
--- a/java/com/google/gerrit/server/restapi/project/CreateProject.java
+++ b/java/com/google/gerrit/server/restapi/project/CreateProject.java
@@ -14,6 +14,8 @@
 
 package com.google.gerrit.server.restapi.project;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
@@ -47,6 +49,7 @@
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.GroupBackend;
 import com.google.gerrit.server.config.AllProjectsName;
+import com.google.gerrit.server.config.AllUsersName;
 import com.google.gerrit.server.config.ProjectOwnerGroupsProvider;
 import com.google.gerrit.server.config.RepositoryConfig;
 import com.google.gerrit.server.extensions.events.AbstractNoNotifyEvent;
@@ -110,6 +113,7 @@
   private final Provider<IdentifiedUser> identifiedUser;
   private final Provider<PutConfig> putConfig;
   private final AllProjectsName allProjects;
+  private final AllUsersName allUsers;
   private final DynamicItem<ProjectNameLockManager> lockManager;
   private final String name;
 
@@ -131,6 +135,7 @@
       Provider<IdentifiedUser> identifiedUser,
       Provider<PutConfig> putConfig,
       AllProjectsName allProjects,
+      AllUsersName allUsers,
       DynamicItem<ProjectNameLockManager> lockManager,
       @Assisted String name) {
     this.projectsCollection = projectsCollection;
@@ -149,6 +154,7 @@
     this.identifiedUser = identifiedUser;
     this.putConfig = putConfig;
     this.allProjects = allProjects;
+    this.allUsers = allUsers;
     this.lockManager = lockManager;
     this.name = name;
   }
@@ -169,6 +175,10 @@
     String parentName =
         MoreObjects.firstNonNull(Strings.emptyToNull(input.parent), allProjects.get());
     args.newParent = projectsCollection.get().parse(parentName, false).getNameKey();
+    if (args.newParent.equals(allUsers)) {
+      throw new ResourceConflictException(
+          String.format("Cannot inherit from '%s' project", allUsers.get()));
+    }
     args.createEmptyCommit = input.createEmptyCommit;
     args.permissionsOnly = input.permissionsOnly;
     args.projectDescription = Strings.emptyToNull(input.description);
@@ -214,6 +224,8 @@
       }
 
       ProjectState projectState = createProject(args);
+      checkNotNull(projectState, "failed to create project " + args.getProject().get());
+
       if (input.pluginConfigValues != null) {
         ConfigInput in = new ConfigInput();
         in.pluginConfigValues = input.pluginConfigValues;
diff --git a/java/com/google/gerrit/server/restapi/project/ListProjects.java b/java/com/google/gerrit/server/restapi/project/ListProjects.java
index 6eb5c88..a1572c6 100644
--- a/java/com/google/gerrit/server/restapi/project/ListProjects.java
+++ b/java/com/google/gerrit/server/restapi/project/ListProjects.java
@@ -413,16 +413,19 @@
               if (!type.matches(git)) {
                 continue;
               }
-              boolean canReadAllRefs;
-              try {
-                permissionBackend
-                    .user(currentUser)
-                    .project(e.getNameKey())
-                    .check(ProjectPermission.READ);
-                canReadAllRefs = true;
-              } catch (AuthException ae) {
-                canReadAllRefs = false;
+
+              boolean canReadAllRefs = e.statePermitsRead();
+              if (canReadAllRefs) {
+                try {
+                  permissionBackend
+                      .user(currentUser)
+                      .project(e.getNameKey())
+                      .check(ProjectPermission.READ);
+                } catch (AuthException exp) {
+                  canReadAllRefs = false;
+                }
               }
+
               List<Ref> refs = getBranchRefs(projectName, canReadAllRefs);
               if (!hasValidRef(refs)) {
                 continue;
diff --git a/java/com/google/gerrit/server/restapi/project/QueryProjects.java b/java/com/google/gerrit/server/restapi/project/QueryProjects.java
index 9a1c36a..64adb0d 100644
--- a/java/com/google/gerrit/server/restapi/project/QueryProjects.java
+++ b/java/com/google/gerrit/server/restapi/project/QueryProjects.java
@@ -21,11 +21,11 @@
 import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.gerrit.extensions.restapi.TopLevelResource;
+import com.google.gerrit.index.project.ProjectData;
+import com.google.gerrit.index.project.ProjectIndex;
+import com.google.gerrit.index.project.ProjectIndexCollection;
 import com.google.gerrit.index.query.QueryParseException;
 import com.google.gerrit.index.query.QueryResult;
-import com.google.gerrit.server.index.project.ProjectIndex;
-import com.google.gerrit.server.index.project.ProjectIndexCollection;
-import com.google.gerrit.server.project.ProjectData;
 import com.google.gerrit.server.project.ProjectJson;
 import com.google.gerrit.server.query.project.ProjectQueryBuilder;
 import com.google.gerrit.server.query.project.ProjectQueryProcessor;
diff --git a/java/com/google/gerrit/server/restapi/project/SetParent.java b/java/com/google/gerrit/server/restapi/project/SetParent.java
index 21fef97..2e51929 100644
--- a/java/com/google/gerrit/server/restapi/project/SetParent.java
+++ b/java/com/google/gerrit/server/restapi/project/SetParent.java
@@ -126,6 +126,11 @@
       throw new ResourceConflictException("cannot set parent of " + allProjects.get());
     }
 
+    if (allUsers.get().equals(newParent)) {
+      throw new ResourceConflictException(
+          String.format("Cannot inherit from '%s' project", allUsers.get()));
+    }
+
     newParent = Strings.emptyToNull(newParent);
     if (newParent != null) {
       ProjectState parent = cache.get(new Project.NameKey(newParent));
diff --git a/java/com/google/gerrit/server/group/db/GroupBundle.java b/java/com/google/gerrit/server/schema/GroupBundle.java
similarity index 74%
rename from java/com/google/gerrit/server/group/db/GroupBundle.java
rename to java/com/google/gerrit/server/schema/GroupBundle.java
index 5d339c0..302ea55 100644
--- a/java/com/google/gerrit/server/group/db/GroupBundle.java
+++ b/java/com/google/gerrit/server/schema/GroupBundle.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.group.db;
+package com.google.gerrit.server.schema;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.collect.ImmutableList.toImmutableList;
@@ -38,12 +38,20 @@
 import com.google.gerrit.reviewdb.client.AccountGroupMember;
 import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
 import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.reviewdb.server.ReviewDbWrapper;
 import com.google.gerrit.server.group.InternalGroup;
+import com.google.gerrit.server.group.db.AuditLogReader;
+import com.google.gerrit.server.group.db.GroupConfig;
+import com.google.gwtorm.jdbc.JdbcSchema;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import java.io.IOException;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
 import java.sql.Timestamp;
+import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.HashSet;
 import java.util.List;
@@ -62,7 +70,7 @@
  * instead.
  */
 @AutoValue
-public abstract class GroupBundle {
+abstract class GroupBundle {
   private static final Logger log = LoggerFactory.getLogger(GroupBundle.class);
 
   static {
@@ -111,20 +119,6 @@
       this.auditLogReader = auditLogReader;
     }
 
-    public GroupBundle fromReviewDb(ReviewDb db, AccountGroup.Id id) throws OrmException {
-      AccountGroup group = db.accountGroups().get(id);
-      if (group == null) {
-        throw new OrmException("Group " + id + " not found");
-      }
-      return create(
-          Source.REVIEW_DB,
-          group,
-          db.accountGroupMembers().byGroup(id).toList(),
-          db.accountGroupMembersAudit().byGroup(id).toList(),
-          db.accountGroupById().byGroup(id).toList(),
-          db.accountGroupByIdAud().byGroup(id).toList());
-    }
-
     public GroupBundle fromNoteDb(Repository repo, AccountGroup.UUID uuid)
         throws ConfigInvalidException, IOException {
       GroupConfig groupConfig = GroupConfig.loadForGroup(repo, uuid);
@@ -161,6 +155,181 @@
               .collect(toImmutableSet()),
           auditLogReader.getSubgroupsAudit(repo, uuid));
     }
+
+    public static GroupBundle fromReviewDb(ReviewDb db, AccountGroup.UUID groupUuid)
+        throws OrmException {
+      JdbcSchema jdbcSchema = ReviewDbWrapper.unwrapJbdcSchema(db);
+      AccountGroup group = readAccountGroupFromReviewDb(jdbcSchema, groupUuid);
+      AccountGroup.Id groupId = group.getId();
+
+      return create(
+          Source.REVIEW_DB,
+          group,
+          readAccountGroupMembersFromReviewDb(jdbcSchema, groupId),
+          readAccountGroupMemberAuditsFromReviewDb(jdbcSchema, groupId),
+          readAccountGroupSubgroupsFromReviewDb(jdbcSchema, groupId),
+          readAccountGroupSubgroupAuditsFromReviewDb(jdbcSchema, groupId));
+    }
+
+    private static AccountGroup readAccountGroupFromReviewDb(
+        JdbcSchema jdbcSchema, AccountGroup.UUID groupUuid) throws OrmException {
+      try (Statement stmt = jdbcSchema.getConnection().createStatement();
+          ResultSet rs =
+              stmt.executeQuery(
+                  "SELECT group_id,"
+                      + " name,"
+                      + " created_on,"
+                      + " description,"
+                      + " owner_group_uuid,"
+                      + " visible_to_all"
+                      + " FROM account_groups"
+                      + " WHERE group_uuid = '"
+                      + groupUuid.get()
+                      + "'")) {
+        if (!rs.next()) {
+          throw new OrmException(String.format("Group %s not found", groupUuid));
+        }
+
+        AccountGroup.Id groupId = new AccountGroup.Id(rs.getInt(1));
+        AccountGroup.NameKey groupName = new AccountGroup.NameKey(rs.getString(2));
+        Timestamp createdOn = rs.getTimestamp(3);
+        String description = rs.getString(4);
+        AccountGroup.UUID ownerGroupUuid = new AccountGroup.UUID(rs.getString(5));
+        boolean visibleToAll = rs.getBoolean(6);
+
+        AccountGroup group = new AccountGroup(groupName, groupId, groupUuid, createdOn);
+        group.setDescription(description);
+        group.setOwnerGroupUUID(ownerGroupUuid);
+        group.setVisibleToAll(visibleToAll);
+
+        if (rs.next()) {
+          throw new OrmException(String.format("Group UUID %s is ambiguous", groupUuid));
+        }
+
+        return group;
+      } catch (SQLException e) {
+        throw new OrmException(
+            String.format("Failed to read account group %s from ReviewDb", groupUuid.get()), e);
+      }
+    }
+
+    private static List<AccountGroupMember> readAccountGroupMembersFromReviewDb(
+        JdbcSchema jdbcSchema, AccountGroup.Id groupId) throws OrmException {
+      try (Statement stmt = jdbcSchema.getConnection().createStatement();
+          ResultSet rs =
+              stmt.executeQuery(
+                  "SELECT account_id"
+                      + " FROM account_group_members"
+                      + " WHERE group_id = '"
+                      + groupId.get()
+                      + "'")) {
+        List<AccountGroupMember> members = new ArrayList<>();
+        while (rs.next()) {
+          Account.Id accountId = new Account.Id(rs.getInt(1));
+          members.add(new AccountGroupMember(new AccountGroupMember.Key(accountId, groupId)));
+        }
+        return members;
+      } catch (SQLException e) {
+        throw new OrmException(
+            String.format(
+                "Failed to read members of account group %s from ReviewDb", groupId.get()),
+            e);
+      }
+    }
+
+    private static List<AccountGroupMemberAudit> readAccountGroupMemberAuditsFromReviewDb(
+        JdbcSchema jdbcSchema, AccountGroup.Id groupId) throws OrmException {
+      try (Statement stmt = jdbcSchema.getConnection().createStatement();
+          ResultSet rs =
+              stmt.executeQuery(
+                  "SELECT account_id, added_by, added_on, removed_by, removed_on"
+                      + " FROM account_group_members_audit"
+                      + " WHERE group_id = '"
+                      + groupId.get()
+                      + "'")) {
+        List<AccountGroupMemberAudit> audits = new ArrayList<>();
+        while (rs.next()) {
+          Account.Id accountId = new Account.Id(rs.getInt(1));
+
+          Account.Id addedBy = new Account.Id(rs.getInt(2));
+          Timestamp addedOn = rs.getTimestamp(3);
+
+          Timestamp removedOn = rs.getTimestamp(5);
+          Account.Id removedBy = removedOn != null ? new Account.Id(rs.getInt(4)) : null;
+
+          AccountGroupMemberAudit.Key key =
+              new AccountGroupMemberAudit.Key(accountId, groupId, addedOn);
+          AccountGroupMemberAudit audit = new AccountGroupMemberAudit(key, addedBy);
+          audit.removed(removedBy, removedOn);
+          audits.add(audit);
+        }
+        return audits;
+      } catch (SQLException e) {
+        throw new OrmException(
+            String.format(
+                "Failed to read member audits of account group %s from ReviewDb", groupId.get()),
+            e);
+      }
+    }
+
+    private static List<AccountGroupById> readAccountGroupSubgroupsFromReviewDb(
+        JdbcSchema jdbcSchema, AccountGroup.Id groupId) throws OrmException {
+      try (Statement stmt = jdbcSchema.getConnection().createStatement();
+          ResultSet rs =
+              stmt.executeQuery(
+                  "SELECT include_uuid"
+                      + " FROM account_group_by_id"
+                      + " WHERE group_id = '"
+                      + groupId.get()
+                      + "'")) {
+        List<AccountGroupById> subgroups = new ArrayList<>();
+        while (rs.next()) {
+          AccountGroup.UUID includedGroupUuid = new AccountGroup.UUID(rs.getString(1));
+          subgroups.add(new AccountGroupById(new AccountGroupById.Key(groupId, includedGroupUuid)));
+        }
+        return subgroups;
+      } catch (SQLException e) {
+        throw new OrmException(
+            String.format(
+                "Failed to read subgroups of account group %s from ReviewDb", groupId.get()),
+            e);
+      }
+    }
+
+    private static List<AccountGroupByIdAud> readAccountGroupSubgroupAuditsFromReviewDb(
+        JdbcSchema jdbcSchema, AccountGroup.Id groupId) throws OrmException {
+      try (Statement stmt = jdbcSchema.getConnection().createStatement();
+          ResultSet rs =
+              stmt.executeQuery(
+                  "SELECT include_uuid, added_by, added_on, removed_by, removed_on"
+                      + " FROM account_group_by_id_aud"
+                      + " WHERE group_id = '"
+                      + groupId.get()
+                      + "'")) {
+        List<AccountGroupByIdAud> audits = new ArrayList<>();
+        while (rs.next()) {
+          AccountGroup.UUID includedGroupUuid = new AccountGroup.UUID(rs.getString(1));
+
+          Account.Id addedBy = new Account.Id(rs.getInt(2));
+          Timestamp addedOn = rs.getTimestamp(3);
+
+          Timestamp removedOn = rs.getTimestamp(5);
+          Account.Id removedBy = removedOn != null ? new Account.Id(rs.getInt(4)) : null;
+
+          AccountGroupByIdAud.Key key =
+              new AccountGroupByIdAud.Key(groupId, includedGroupUuid, addedOn);
+          AccountGroupByIdAud audit = new AccountGroupByIdAud(key, addedBy);
+          audit.removed(removedBy, removedOn);
+          audits.add(audit);
+        }
+        return audits;
+      } catch (SQLException e) {
+        throw new OrmException(
+            String.format(
+                "Failed to read subgroup audits of account group %s from ReviewDb", groupId.get()),
+            e);
+      }
+    }
   }
 
   private static final Comparator<AccountGroupMember> ACCOUNT_GROUP_MEMBER_COMPARATOR =
diff --git a/java/com/google/gerrit/server/group/db/GroupRebuilder.java b/java/com/google/gerrit/server/schema/GroupRebuilder.java
similarity index 86%
rename from java/com/google/gerrit/server/group/db/GroupRebuilder.java
rename to java/com/google/gerrit/server/schema/GroupRebuilder.java
index 3753d72..7c092b7 100644
--- a/java/com/google/gerrit/server/group/db/GroupRebuilder.java
+++ b/java/com/google/gerrit/server/schema/GroupRebuilder.java
@@ -12,14 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.group.db;
+package com.google.gerrit.server.schema;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.collect.ImmutableSet.toImmutableSet;
 
 import com.google.auto.value.AutoValue;
-import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.ListMultimap;
@@ -31,19 +30,18 @@
 import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.reviewdb.client.AccountGroupByIdAud;
 import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
-import com.google.gerrit.server.GerritPersonIdent;
-import com.google.gerrit.server.account.AccountCache;
-import com.google.gerrit.server.account.GroupBackend;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.config.AllUsersName;
-import com.google.gerrit.server.config.GerritServerId;
+import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
 import com.google.gerrit.server.git.MetaDataUpdate;
 import com.google.gerrit.server.git.VersionedMetaData.BatchMetaDataUpdate;
+import com.google.gerrit.server.group.db.AuditLogFormatter;
+import com.google.gerrit.server.group.db.GroupConfig;
+import com.google.gerrit.server.group.db.InternalGroupCreation;
+import com.google.gerrit.server.group.db.InternalGroupUpdate;
 import com.google.gerrit.server.group.db.InternalGroupUpdate.MemberModification;
 import com.google.gerrit.server.group.db.InternalGroupUpdate.SubgroupModification;
 import com.google.gwtorm.server.OrmDuplicateKeyException;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import com.google.inject.Singleton;
 import java.io.IOException;
 import java.sql.Timestamp;
 import java.util.Collection;
@@ -60,40 +58,15 @@
 import org.eclipse.jgit.lib.Repository;
 
 /** Helper for rebuilding an entire group's NoteDb refs. */
-@Singleton
-public class GroupRebuilder {
-  private final Provider<PersonIdent> serverIdent;
+class GroupRebuilder {
+  private final PersonIdent serverIdent;
   private final AllUsersName allUsers;
-  private final MetaDataUpdate.InternalFactory metaDataUpdateFactory;
-
   private final AuditLogFormatter auditLogFormatter;
 
-  @Inject
-  GroupRebuilder(
-      @GerritPersonIdent Provider<PersonIdent> serverIdent,
-      @GerritServerId String serverId,
-      AllUsersName allUsers,
-      MetaDataUpdate.InternalFactory metaDataUpdateFactory,
-      AccountCache accountCache,
-      GroupBackend groupBackend) {
-    this(
-        serverIdent,
-        allUsers,
-        metaDataUpdateFactory,
-
-        // TODO(dborowitz): These probably won't work during init.
-        AuditLogFormatter.createBackedBy(accountCache, groupBackend, serverId));
-  }
-
-  @VisibleForTesting
-  GroupRebuilder(
-      Provider<PersonIdent> serverIdent,
-      AllUsersName allUsers,
-      MetaDataUpdate.InternalFactory metaDataUpdateFactory,
-      AuditLogFormatter auditLogFormatter) {
+  public GroupRebuilder(
+      PersonIdent serverIdent, AllUsersName allUsers, AuditLogFormatter auditLogFormatter) {
     this.serverIdent = serverIdent;
     this.allUsers = allUsers;
-    this.metaDataUpdateFactory = metaDataUpdateFactory;
     this.auditLogFormatter = auditLogFormatter;
   }
 
@@ -122,7 +95,7 @@
     Map<Key, Collection<Event>> events = toEvents(bundle).asMap();
     PersonIdent nowServerIdent = getServerIdent(events);
 
-    MetaDataUpdate md = metaDataUpdateFactory.create(allUsers, allUsersRepo, bru);
+    MetaDataUpdate md = createMetaDataUpdate(allUsers, allUsersRepo, bru);
 
     // Creation is done by the server (unlike later audit events).
     PersonIdent created = new PersonIdent(nowServerIdent, group.getCreatedOn());
@@ -207,12 +180,17 @@
     // Created with MultimapBuilder.treeKeys, so the keySet is navigable.
     Key lastKey = ((NavigableSet<Key>) events.keySet()).last();
     checkState(lastKey.type() == Type.FIXUP);
-    PersonIdent ident = serverIdent.get();
     return new PersonIdent(
-        ident.getName(),
-        ident.getEmailAddress(),
+        serverIdent.getName(),
+        serverIdent.getEmailAddress(),
         Iterables.getOnlyElement(events.get(lastKey)).when(),
-        ident.getTimeZone());
+        serverIdent.getTimeZone());
+  }
+
+  private static MetaDataUpdate createMetaDataUpdate(
+      Project.NameKey projectName, Repository repository, @Nullable BatchRefUpdate batchRefUpdate) {
+    return new MetaDataUpdate(
+        GitReferenceUpdated.DISABLED, projectName, repository, batchRefUpdate);
   }
 
   private static Consumer<InternalGroupUpdate.Builder> addMember(Account.Id toAdd) {
diff --git a/java/com/google/gerrit/server/schema/Schema_160.java b/java/com/google/gerrit/server/schema/Schema_160.java
index b65870f..c5a4422 100644
--- a/java/com/google/gerrit/server/schema/Schema_160.java
+++ b/java/com/google/gerrit/server/schema/Schema_160.java
@@ -18,6 +18,7 @@
 import static com.google.gerrit.server.git.UserConfigSections.MY;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableList;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.RefNames;
 import com.google.gerrit.reviewdb.server.ReviewDb;
@@ -40,17 +41,34 @@
 import org.eclipse.jgit.lib.TextProgressMonitor;
 
 /**
- * Remove "My Drafts" menu items for all users.
+ * Remove "My Drafts" menu items for all users and server-wide default preferences.
  *
  * <p>Since draft changes no longer exist, these menu items are obsolete.
  *
- * <p>Only matches menu items (with any name) where the URL exactly matches the <a
+ * <p>Only matches menu items (with any name) where the URL exactly matches one of the following,
+ * with or without leading {@code #}:
+ *
+ * <ul>
+ *   <li>/q/is:draft
+ *   <li>/q/owner:self+is:draft
+ * </ul>
+ *
+ * In particular, this includes the <a
  * href="https://gerrit.googlesource.com/gerrit/+/v2.14.4/gerrit-server/src/main/java/com/google/gerrit/server/account/GeneralPreferencesLoader.java#144">default
- * version from 2.14 and earlier</a>. Other menus containing {@code is:draft} in other positions are
- * not affected; this is still a valid predicate that matches no changes.
+ * from version 2.14 and earlier</a>.
+ *
+ * <p>Other menus containing {@code is:draft} in other positions are not affected; this is still a
+ * valid predicate that matches no changes.
  */
 public class Schema_160 extends SchemaVersion {
-  @VisibleForTesting static final String DEFAULT_DRAFT_ITEM = "#/q/owner:self+is:draft";
+  @VisibleForTesting static final ImmutableList<String> DEFAULT_DRAFT_ITEMS;
+
+  static {
+    String ownerSelfIsDraft = "/q/owner:self+is:draft";
+    String isDraft = "/q/is:draft";
+    DEFAULT_DRAFT_ITEMS =
+        ImmutableList.of(ownerSelfIsDraft, '#' + ownerSelfIsDraft, isDraft, '#' + isDraft);
+  }
 
   private final GitRepositoryManager repoManager;
   private final AllUsersName allUsersName;
@@ -75,10 +93,9 @@
         ProgressMonitor pm = new TextProgressMonitor();
         pm.beginTask("Removing \"My Drafts\" menu items", ProgressMonitor.UNKNOWN);
         for (Account.Id id : (Iterable<Account.Id>) Accounts.readUserRefs(repo)::iterator) {
-          if (removeMyDrafts(repo, id)) {
-            pm.update(1);
-          }
+          removeMyDrafts(repo, RefNames.refsUsers(id), pm);
         }
+        removeMyDrafts(repo, RefNames.REFS_USERS_DEFAULT, pm);
         pm.endTask();
       }
     } catch (IOException | ConfigInvalidException e) {
@@ -86,24 +103,26 @@
     }
   }
 
-  private boolean removeMyDrafts(Repository repo, Account.Id id)
+  private void removeMyDrafts(Repository repo, String ref, ProgressMonitor pm)
       throws IOException, ConfigInvalidException {
     MetaDataUpdate md = new MetaDataUpdate(GitReferenceUpdated.DISABLED, allUsersName, repo);
     PersonIdent ident = serverIdent.get();
     md.getCommitBuilder().setAuthor(ident);
     md.getCommitBuilder().setCommitter(ident);
-    Prefs prefs = new Prefs(id);
+    Prefs prefs = new Prefs(ref);
     prefs.load(repo);
     prefs.removeMyDrafts();
     prefs.commit(md);
-    return prefs.dirty();
+    if (prefs.dirty()) {
+      pm.update(1);
+    }
   }
 
   private static class Prefs extends VersionedAccountPreferences {
     private boolean dirty;
 
-    Prefs(Account.Id id) {
-      super(RefNames.refsUsers(id));
+    Prefs(String ref) {
+      super(ref);
     }
 
     @Override
@@ -118,7 +137,8 @@
     void removeMyDrafts() {
       Config cfg = getConfig();
       for (String item : cfg.getSubsections(MY)) {
-        if (DEFAULT_DRAFT_ITEM.equals(cfg.getString(MY, item, KEY_URL))) {
+        String value = cfg.getString(MY, item, KEY_URL);
+        if (DEFAULT_DRAFT_ITEMS.contains(value)) {
           cfg.unsetSection(MY, item);
           dirty = true;
         }
diff --git a/java/com/google/gerrit/server/schema/VersionedAccountPreferences.java b/java/com/google/gerrit/server/schema/VersionedAccountPreferences.java
index d57b14d..0213f3b 100644
--- a/java/com/google/gerrit/server/schema/VersionedAccountPreferences.java
+++ b/java/com/google/gerrit/server/schema/VersionedAccountPreferences.java
@@ -25,12 +25,16 @@
 
 /** Preferences for user accounts during schema migrations. */
 class VersionedAccountPreferences extends VersionedMetaData {
-  private static final String PREFERENCES = "preferences.config";
+  static final String PREFERENCES = "preferences.config";
 
   static VersionedAccountPreferences forUser(Account.Id id) {
     return new VersionedAccountPreferences(RefNames.refsUsers(id));
   }
 
+  static VersionedAccountPreferences forDefault() {
+    return new VersionedAccountPreferences(RefNames.REFS_USERS_DEFAULT);
+  }
+
   private final String ref;
   private Config cfg;
 
diff --git a/java/com/google/gerrit/server/update/BatchUpdateReviewDb.java b/java/com/google/gerrit/server/update/BatchUpdateReviewDb.java
index 3b8f871..7d99b44 100644
--- a/java/com/google/gerrit/server/update/BatchUpdateReviewDb.java
+++ b/java/com/google/gerrit/server/update/BatchUpdateReviewDb.java
@@ -37,10 +37,6 @@
     return ReviewDbUtil.unwrapDb(db);
   }
 
-  public ReviewDb unsafeGetDelegate() {
-    return delegate;
-  }
-
   @Override
   public ChangeAccess changes() {
     return changesWrapper;
diff --git a/java/com/google/gerrit/sshd/commands/UploadArchive.java b/java/com/google/gerrit/sshd/commands/UploadArchive.java
index 9ac522f..c838c16 100644
--- a/java/com/google/gerrit/sshd/commands/UploadArchive.java
+++ b/java/com/google/gerrit/sshd/commands/UploadArchive.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.sshd.commands;
 
+import static com.google.common.base.Preconditions.checkNotNull;
 import static java.nio.charset.StandardCharsets.UTF_8;
 
 import com.google.common.base.Splitter;
@@ -23,6 +24,8 @@
 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.project.ProjectCache;
+import com.google.gerrit.server.project.ProjectState;
 import com.google.gerrit.server.restapi.change.AllowedFormats;
 import com.google.gerrit.server.restapi.project.CommitsCollection;
 import com.google.gerrit.sshd.AbstractGitCommand;
@@ -123,6 +126,7 @@
   @Inject private PermissionBackend permissionBackend;
   @Inject private CommitsCollection commits;
   @Inject private AllowedFormats allowedFormats;
+  @Inject private ProjectCache projectCache;
   private Options options = new Options();
 
   /**
@@ -242,6 +246,13 @@
   }
 
   private boolean canRead(ObjectId revId) throws IOException, PermissionBackendException {
+    ProjectState projectState = projectCache.get(projectName);
+    checkNotNull(projectState, "Failed to load project %s", projectName);
+
+    if (!projectState.statePermitsRead()) {
+      return false;
+    }
+
     try {
       permissionBackend.user(user).project(projectName).check(ProjectPermission.READ);
       return true;
diff --git a/java/com/google/gerrit/testing/BUILD b/java/com/google/gerrit/testing/BUILD
index 59102a9..9846825 100644
--- a/java/com/google/gerrit/testing/BUILD
+++ b/java/com/google/gerrit/testing/BUILD
@@ -17,6 +17,7 @@
         "//java/com/google/gerrit/extensions:api",
         "//java/com/google/gerrit/gpg",
         "//java/com/google/gerrit/index",
+        "//java/com/google/gerrit/index/project",
         "//java/com/google/gerrit/lifecycle",
         "//java/com/google/gerrit/metrics",
         "//java/com/google/gerrit/pgm/init",
diff --git a/java/com/google/gerrit/testing/FakeAccountCache.java b/java/com/google/gerrit/testing/FakeAccountCache.java
index a3b4d90..e549e08 100644
--- a/java/com/google/gerrit/testing/FakeAccountCache.java
+++ b/java/com/google/gerrit/testing/FakeAccountCache.java
@@ -60,7 +60,7 @@
   }
 
   @Override
-  public synchronized void evictAllNoReindex() {
+  public synchronized void evictAll() {
     byId.clear();
   }
 
diff --git a/java/com/google/gerrit/testing/GitTestUtil.java b/java/com/google/gerrit/testing/GitTestUtil.java
new file mode 100644
index 0000000..71dd725
--- /dev/null
+++ b/java/com/google/gerrit/testing/GitTestUtil.java
@@ -0,0 +1,51 @@
+// 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.testing;
+
+import static com.google.common.collect.ImmutableList.toImmutableList;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Streams;
+import com.google.gerrit.extensions.common.CommitInfo;
+import com.google.gerrit.server.git.CommitUtil;
+import java.io.IOException;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevSort;
+import org.eclipse.jgit.revwalk.RevWalk;
+
+public class GitTestUtil {
+  public static ImmutableList<CommitInfo> log(Repository repo, String refName) throws Exception {
+    try (RevWalk rw = new RevWalk(repo)) {
+      Ref ref = repo.exactRef(refName);
+      if (ref != null) {
+        rw.sort(RevSort.REVERSE);
+        rw.markStart(rw.parseCommit(ref.getObjectId()));
+        return Streams.stream(rw)
+            .map(
+                c -> {
+                  try {
+                    return CommitUtil.toCommitInfo(c);
+                  } catch (IOException e) {
+                    throw new IllegalStateException(
+                        "unexpected state when converting commit " + c.getName(), e);
+                  }
+                })
+            .collect(toImmutableList());
+      }
+    }
+    return ImmutableList.of();
+  }
+}
diff --git a/java/com/google/gerrit/testing/InMemoryModule.java b/java/com/google/gerrit/testing/InMemoryModule.java
index 3bea0a8..ea4b174 100644
--- a/java/com/google/gerrit/testing/InMemoryModule.java
+++ b/java/com/google/gerrit/testing/InMemoryModule.java
@@ -24,6 +24,7 @@
 import com.google.gerrit.extensions.systemstatus.ServerInformation;
 import com.google.gerrit.gpg.GpgModule;
 import com.google.gerrit.index.SchemaDefinitions;
+import com.google.gerrit.index.project.ProjectSchemaDefinitions;
 import com.google.gerrit.metrics.DisabledMetricMaker;
 import com.google.gerrit.metrics.MetricMaker;
 import com.google.gerrit.reviewdb.server.ReviewDb;
@@ -41,6 +42,7 @@
 import com.google.gerrit.server.config.CanonicalWebUrlModule;
 import com.google.gerrit.server.config.CanonicalWebUrlProvider;
 import com.google.gerrit.server.config.GerritGlobalModule;
+import com.google.gerrit.server.config.GerritInstanceNameModule;
 import com.google.gerrit.server.config.GerritOptions;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.GerritServerId;
@@ -60,7 +62,6 @@
 import com.google.gerrit.server.index.change.ChangeSchemaDefinitions;
 import com.google.gerrit.server.index.group.AllGroupsIndexer;
 import com.google.gerrit.server.index.group.GroupSchemaDefinitions;
-import com.google.gerrit.server.index.project.ProjectSchemaDefinitions;
 import com.google.gerrit.server.mail.SignedTokenEmailTokenVerifier;
 import com.google.gerrit.server.notedb.ChangeBundleReader;
 import com.google.gerrit.server.notedb.GwtormChangeBundleReader;
@@ -203,6 +204,7 @@
     bind(Key.get(schemaFactory, ReviewDbFactory.class)).to(InMemoryDatabase.class);
 
     install(NoSshKeyCache.module());
+    install(new GerritInstanceNameModule());
     install(
         new CanonicalWebUrlModule() {
           @Override
diff --git a/java/com/google/gerrit/testing/NoteDbChecker.java b/java/com/google/gerrit/testing/NoteDbChecker.java
index 77d581b..b5dd9e9 100644
--- a/java/com/google/gerrit/testing/NoteDbChecker.java
+++ b/java/com/google/gerrit/testing/NoteDbChecker.java
@@ -19,6 +19,8 @@
 import static java.util.stream.Collectors.toList;
 
 import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableListMultimap;
+import com.google.common.collect.ListMultimap;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.client.RefNames;
@@ -78,14 +80,17 @@
   }
 
   public void rebuildAndCheckAllChanges() throws Exception {
-    rebuildAndCheckChanges(getUnwrappedDb().changes().all().toList().stream().map(Change::getId));
+    rebuildAndCheckChanges(
+        getUnwrappedDb().changes().all().toList().stream().map(Change::getId),
+        ImmutableListMultimap.of());
   }
 
   public void rebuildAndCheckChanges(Change.Id... changeIds) throws Exception {
-    rebuildAndCheckChanges(Arrays.stream(changeIds));
+    rebuildAndCheckChanges(Arrays.stream(changeIds), ImmutableListMultimap.of());
   }
 
-  private void rebuildAndCheckChanges(Stream<Change.Id> changeIds) throws Exception {
+  private void rebuildAndCheckChanges(
+      Stream<Change.Id> changeIds, ListMultimap<Change.Id, String> expectedDiffs) throws Exception {
     ReviewDb db = getUnwrappedDb();
 
     List<ChangeBundle> allExpected = readExpected(changeIds);
@@ -105,7 +110,7 @@
         }
       }
 
-      checkActual(allExpected, msgs);
+      checkActual(allExpected, expectedDiffs, msgs);
     } finally {
       notesMigration.setReadChanges(oldRead);
       notesMigration.setWriteChanges(oldWrite);
@@ -113,7 +118,14 @@
   }
 
   public void checkChanges(Change.Id... changeIds) throws Exception {
-    checkActual(readExpected(Arrays.stream(changeIds)), new ArrayList<>());
+    checkActual(
+        readExpected(Arrays.stream(changeIds)), ImmutableListMultimap.of(), new ArrayList<>());
+  }
+
+  public void rebuildAndCheckChange(Change.Id changeId, String... expectedDiff) throws Exception {
+    ImmutableListMultimap.Builder<Change.Id, String> b = ImmutableListMultimap.builder();
+    b.putAll(changeId, Arrays.asList(expectedDiff));
+    rebuildAndCheckChanges(Stream.of(changeId), b.build());
   }
 
   public void assertNoChangeRef(Project.NameKey project, Change.Id changeId) throws Exception {
@@ -160,7 +172,11 @@
     }
   }
 
-  private void checkActual(List<ChangeBundle> allExpected, List<String> msgs) throws Exception {
+  private void checkActual(
+      List<ChangeBundle> allExpected,
+      ListMultimap<Change.Id, String> expectedDiffs,
+      List<String> msgs)
+      throws Exception {
     ReviewDb db = getUnwrappedDb();
     boolean oldRead = notesMigration.readChanges();
     boolean oldWrite = notesMigration.rawWriteChangesSetting();
@@ -181,9 +197,14 @@
           continue;
         }
         List<String> diff = expected.differencesFrom(actual);
-        if (!diff.isEmpty()) {
+        List<String> expectedDiff = expectedDiffs.get(c.getId());
+        if (!diff.equals(expectedDiff)) {
           msgs.add("Differences between ReviewDb and NoteDb for " + c + ":");
           msgs.addAll(diff);
+          if (!expectedDiff.isEmpty()) {
+            msgs.add("Expected differences:");
+            msgs.addAll(expectedDiff);
+          }
           msgs.add("");
         } else {
           System.err.println("NoteDb conversion of change " + c.getId() + " successful");
diff --git a/javatests/com/google/gerrit/acceptance/ProjectResetterTest.java b/javatests/com/google/gerrit/acceptance/ProjectResetterTest.java
index 74b23a4..fce28de 100644
--- a/javatests/com/google/gerrit/acceptance/ProjectResetterTest.java
+++ b/javatests/com/google/gerrit/acceptance/ProjectResetterTest.java
@@ -25,6 +25,7 @@
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.config.AllUsersName;
 import com.google.gerrit.server.config.AllUsersNameProvider;
+import com.google.gerrit.server.index.account.AccountIndexer;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.testing.GerritBaseTests;
 import com.google.gerrit.testing.InMemoryRepositoryManager;
@@ -223,7 +224,7 @@
     Ref nonMetaConfig = createRef("refs/heads/master");
 
     try (ProjectResetter resetProject =
-        builder(null, null, projectCache)
+        builder(null, null, null, projectCache)
             .build(new ProjectResetter.Config().reset(project).reset(project2))) {
       updateRef(nonMetaConfig);
       updateRef(repo2, metaConfig);
@@ -243,7 +244,7 @@
     EasyMock.replay(projectCache);
 
     try (ProjectResetter resetProject =
-        builder(null, null, projectCache)
+        builder(null, null, null, projectCache)
             .build(new ProjectResetter.Config().reset(project).reset(project2))) {
       createRef("refs/heads/master");
       createRef(repo2, RefNames.REFS_CONFIG);
@@ -264,17 +265,22 @@
     EasyMock.expectLastCall();
     EasyMock.replay(accountCache);
 
+    AccountIndexer accountIndexer = EasyMock.createNiceMock(AccountIndexer.class);
+    accountIndexer.index(accountId);
+    EasyMock.expectLastCall();
+    EasyMock.replay(accountIndexer);
+
     // Non-user branch because it's not in All-Users.
     Ref nonUserBranch = createRef(RefNames.refsUsers(new Account.Id(2)));
 
     try (ProjectResetter resetProject =
-        builder(null, accountCache, null)
+        builder(null, accountCache, accountIndexer, null)
             .build(new ProjectResetter.Config().reset(project).reset(allUsers))) {
       updateRef(nonUserBranch);
       updateRef(allUsersRepo, userBranch);
     }
 
-    EasyMock.verify(accountCache);
+    EasyMock.verify(accountCache, accountIndexer);
   }
 
   @Test
@@ -288,8 +294,13 @@
     EasyMock.expectLastCall();
     EasyMock.replay(accountCache);
 
+    AccountIndexer accountIndexer = EasyMock.createNiceMock(AccountIndexer.class);
+    accountIndexer.index(accountId);
+    EasyMock.expectLastCall();
+    EasyMock.replay(accountIndexer);
+
     try (ProjectResetter resetProject =
-        builder(null, accountCache, null)
+        builder(null, accountCache, accountIndexer, null)
             .build(new ProjectResetter.Config().reset(project).reset(allUsers))) {
       // Non-user branch because it's not in All-Users.
       createRef(RefNames.refsUsers(new Account.Id(2)));
@@ -297,7 +308,7 @@
       createRef(allUsersRepo, RefNames.refsUsers(accountId));
     }
 
-    EasyMock.verify(accountCache);
+    EasyMock.verify(accountCache, accountIndexer);
   }
 
   @Test
@@ -317,18 +328,25 @@
     EasyMock.expectLastCall();
     EasyMock.replay(accountCache);
 
+    AccountIndexer accountIndexer = EasyMock.createNiceMock(AccountIndexer.class);
+    accountIndexer.index(accountId);
+    EasyMock.expectLastCall();
+    accountIndexer.index(accountId2);
+    EasyMock.expectLastCall();
+    EasyMock.replay(accountIndexer);
+
     // Non-user branch because it's not in All-Users.
     Ref nonUserBranch = createRef(RefNames.refsUsers(new Account.Id(3)));
 
     try (ProjectResetter resetProject =
-        builder(null, accountCache, null)
+        builder(null, accountCache, accountIndexer, null)
             .build(new ProjectResetter.Config().reset(project).reset(allUsers))) {
       updateRef(nonUserBranch);
       updateRef(allUsersRepo, externalIds);
       createRef(allUsersRepo, RefNames.refsUsers(accountId2));
     }
 
-    EasyMock.verify(accountCache);
+    EasyMock.verify(accountCache, accountIndexer);
   }
 
   @Test
@@ -347,18 +365,25 @@
     EasyMock.expectLastCall();
     EasyMock.replay(accountCache);
 
+    AccountIndexer accountIndexer = EasyMock.createNiceMock(AccountIndexer.class);
+    accountIndexer.index(accountId);
+    EasyMock.expectLastCall();
+    accountIndexer.index(accountId2);
+    EasyMock.expectLastCall();
+    EasyMock.replay(accountIndexer);
+
     // Non-user branch because it's not in All-Users.
     Ref nonUserBranch = createRef(RefNames.refsUsers(new Account.Id(3)));
 
     try (ProjectResetter resetProject =
-        builder(null, accountCache, null)
+        builder(null, accountCache, accountIndexer, null)
             .build(new ProjectResetter.Config().reset(project).reset(allUsers))) {
       updateRef(nonUserBranch);
       createRef(allUsersRepo, RefNames.REFS_EXTERNAL_IDS);
       createRef(allUsersRepo, RefNames.refsUsers(accountId2));
     }
 
-    EasyMock.verify(accountCache);
+    EasyMock.verify(accountCache, accountIndexer);
   }
 
   @Test
@@ -373,7 +398,7 @@
     EasyMock.replay(accountCreator);
 
     try (ProjectResetter resetProject =
-        builder(accountCreator, null, null)
+        builder(accountCreator, null, null, null)
             .build(new ProjectResetter.Config().reset(project).reset(allUsers))) {
       createRef(allUsersRepo, RefNames.refsUsers(accountId));
     }
@@ -449,18 +474,20 @@
   }
 
   private ProjectResetter.Builder builder() {
-    return builder(null, null, null);
+    return builder(null, null, null, null);
   }
 
   private ProjectResetter.Builder builder(
       @Nullable AccountCreator accountCreator,
       @Nullable AccountCache accountCache,
+      @Nullable AccountIndexer accountIndexer,
       @Nullable ProjectCache projectCache) {
     return new ProjectResetter.Builder(
         repoManager,
         new AllUsersName(AllUsersNameProvider.DEFAULT),
         accountCreator,
         accountCache,
+        accountIndexer,
         projectCache);
   }
 }
diff --git a/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java b/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java
index f8781b5..83d166a 100644
--- a/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java
@@ -1982,13 +1982,11 @@
     assertGroups(
         admin.username, ImmutableList.of("Anonymous Users", "Registered Users", "Administrators"));
 
-    // TODO: update when test user is fixed to be included in "Anonymous Users" and
-    //      "Registered Users" groups
-    assertGroups(user.username, ImmutableList.of());
+    assertGroups(user.username, ImmutableList.of("Anonymous Users", "Registered Users"));
 
     String group = createGroup("group");
     String newUser = createAccount("user1", group);
-    assertGroups(newUser, ImmutableList.of(group));
+    assertGroups(newUser, ImmutableList.of("Anonymous Users", "Registered Users", group));
   }
 
   @Test
@@ -2367,11 +2365,14 @@
   }
 
   private void assertGroups(String user, List<String> expected) throws Exception {
-    List<String> actual =
-        gApi.accounts().id(user).getGroups().stream().map(g -> g.name).collect(toList());
+    List<String> actual = getNamesOfGroupsOfUser(user);
     assertThat(actual).containsExactlyElementsIn(expected);
   }
 
+  private List<String> getNamesOfGroupsOfUser(String user) throws RestApiException {
+    return gApi.accounts().id(user).getGroups().stream().map(g -> g.name).collect(toList());
+  }
+
   private void assertSequenceNumbers(List<SshKeyInfo> sshKeys) {
     int seq = 1;
     for (SshKeyInfo key : sshKeys) {
diff --git a/javatests/com/google/gerrit/acceptance/api/accounts/AccountIndexerIT.java b/javatests/com/google/gerrit/acceptance/api/accounts/AccountIndexerIT.java
new file mode 100644
index 0000000..310a1e19
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/api/accounts/AccountIndexerIT.java
@@ -0,0 +1,170 @@
+// 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.api.accounts;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import com.google.gerrit.extensions.api.GerritApi;
+import com.google.gerrit.extensions.common.AccountInfo;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.server.GerritPersonIdent;
+import com.google.gerrit.server.account.AccountCache;
+import com.google.gerrit.server.account.AccountConfig;
+import com.google.gerrit.server.account.AccountState;
+import com.google.gerrit.server.account.InternalAccountUpdate;
+import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.git.MetaDataUpdate;
+import com.google.gerrit.server.index.account.AccountIndexer;
+import com.google.gerrit.server.query.account.InternalAccountQuery;
+import com.google.gerrit.testing.InMemoryTestEnvironment;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import java.io.IOException;
+import java.util.List;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Repository;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class AccountIndexerIT {
+  @Rule public InMemoryTestEnvironment testEnvironment = new InMemoryTestEnvironment();
+
+  @Inject private AccountIndexer accountIndexer;
+  @Inject private GerritApi gApi;
+  @Inject private AccountCache accountCache;
+  @Inject private Provider<InternalAccountQuery> accountQueryProvider;
+  @Inject private GitRepositoryManager repoManager;
+  @Inject private AllUsersName allUsersName;
+  @Inject @GerritPersonIdent protected Provider<PersonIdent> serverIdent;
+
+  @Test
+  public void indexingUpdatesTheIndex() throws Exception {
+    Account.Id accountId = createAccount("foo");
+    String preferredEmail = "foo@example.com";
+    updateAccountWithoutCacheOrIndex(
+        accountId, newAccountUpdate().setPreferredEmail(preferredEmail).build());
+    assertThat(accountQueryProvider.get().byPreferredEmail(preferredEmail)).isEmpty();
+
+    accountIndexer.index(accountId);
+    List<AccountState> matchedAccountStates =
+        accountQueryProvider.get().byPreferredEmail(preferredEmail);
+    assertThat(matchedAccountStates).hasSize(1);
+    assertThat(matchedAccountStates.get(0).getAccount().getId()).isEqualTo(accountId);
+  }
+
+  @Test
+  public void indexCannotBeCorruptedByStaleCache() throws Exception {
+    Account.Id accountId = createAccount("foo");
+    loadAccountToCache(accountId);
+    String preferredEmail = "foo@example.com";
+    updateAccountWithoutCacheOrIndex(
+        accountId, newAccountUpdate().setPreferredEmail(preferredEmail).build());
+    assertThat(accountQueryProvider.get().byPreferredEmail(preferredEmail)).isEmpty();
+
+    accountIndexer.index(accountId);
+    List<AccountState> matchedAccountStates =
+        accountQueryProvider.get().byPreferredEmail(preferredEmail);
+    assertThat(matchedAccountStates).hasSize(1);
+    assertThat(matchedAccountStates.get(0).getAccount().getId()).isEqualTo(accountId);
+  }
+
+  @Test
+  public void indexingUpdatesStaleCache() throws Exception {
+    Account.Id accountId = createAccount("foo");
+    loadAccountToCache(accountId);
+    String status = "ooo";
+    updateAccountWithoutCacheOrIndex(accountId, newAccountUpdate().setStatus(status).build());
+    assertThat(accountCache.get(accountId).get().getAccount().getStatus()).isNull();
+
+    accountIndexer.index(accountId);
+    assertThat(accountCache.get(accountId).get().getAccount().getStatus()).isEqualTo(status);
+  }
+
+  @Test
+  public void reindexingStaleAccountUpdatesTheIndex() throws Exception {
+    Account.Id accountId = createAccount("foo");
+    String preferredEmail = "foo@example.com";
+    updateAccountWithoutCacheOrIndex(
+        accountId, newAccountUpdate().setPreferredEmail(preferredEmail).build());
+    assertThat(accountQueryProvider.get().byPreferredEmail(preferredEmail)).isEmpty();
+
+    accountIndexer.reindexIfStale(accountId);
+    List<AccountState> matchedAccountStates =
+        accountQueryProvider.get().byPreferredEmail(preferredEmail);
+    assertThat(matchedAccountStates).hasSize(1);
+    assertThat(matchedAccountStates.get(0).getAccount().getId()).isEqualTo(accountId);
+  }
+
+  @Test
+  public void notStaleAccountIsNotReindexed() throws Exception {
+    Account.Id accountId = createAccount("foo");
+    updateAccountWithoutCacheOrIndex(
+        accountId, newAccountUpdate().setPreferredEmail("foo@example.com").build());
+    accountIndexer.index(accountId);
+
+    boolean reindexed = accountIndexer.reindexIfStale(accountId);
+    assertWithMessage("Account should not have been reindexed").that(reindexed).isFalse();
+  }
+
+  @Test
+  public void indexStalenessIsNotDerivedFromCacheStaleness() throws Exception {
+    Account.Id accountId = createAccount("foo");
+    updateAccountWithoutCacheOrIndex(
+        accountId, newAccountUpdate().setPreferredEmail("foo@example.com").build());
+    reloadAccountToCache(accountId);
+
+    boolean reindexed = accountIndexer.reindexIfStale(accountId);
+    assertWithMessage("Account should have been reindexed").that(reindexed).isTrue();
+  }
+
+  private Account.Id createAccount(String name) throws RestApiException {
+    AccountInfo account = gApi.accounts().create(name).get();
+    return new Account.Id(account._accountId);
+  }
+
+  private void reloadAccountToCache(Account.Id accountId) {
+    accountCache.evict(accountId);
+    loadAccountToCache(accountId);
+  }
+
+  private void loadAccountToCache(Account.Id accountId) {
+    accountCache.get(accountId);
+  }
+
+  private static InternalAccountUpdate.Builder newAccountUpdate() {
+    return InternalAccountUpdate.builder();
+  }
+
+  private void updateAccountWithoutCacheOrIndex(
+      Account.Id accountId, InternalAccountUpdate accountUpdate)
+      throws IOException, ConfigInvalidException {
+    try (Repository allUsersRepo = repoManager.openRepository(allUsersName);
+        MetaDataUpdate md =
+            new MetaDataUpdate(GitReferenceUpdated.DISABLED, allUsersName, allUsersRepo)) {
+      PersonIdent ident = serverIdent.get();
+      md.getCommitBuilder().setAuthor(ident);
+      md.getCommitBuilder().setCommitter(ident);
+
+      AccountConfig accountConfig = new AccountConfig(accountId, allUsersRepo).load();
+      accountConfig.setAccountUpdate(accountUpdate);
+      accountConfig.commit(md);
+    }
+  }
+}
diff --git a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
index 8f27de3..3607efc 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -80,6 +80,7 @@
 import com.google.gerrit.extensions.api.changes.NotifyInfo;
 import com.google.gerrit.extensions.api.changes.RebaseInput;
 import com.google.gerrit.extensions.api.changes.RecipientType;
+import com.google.gerrit.extensions.api.changes.RevertInput;
 import com.google.gerrit.extensions.api.changes.ReviewInput;
 import com.google.gerrit.extensions.api.changes.ReviewInput.DraftHandling;
 import com.google.gerrit.extensions.api.changes.ReviewResult;
@@ -168,7 +169,6 @@
 import org.eclipse.jgit.transport.PushResult;
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 
 @NoHttpd
@@ -418,6 +418,17 @@
   }
 
   @Test
+  public void setWorkInProgressAllowedAsAdmin() throws Exception {
+    setApiUser(user);
+    String changeId =
+        gApi.changes().create(new ChangeInput(project.get(), "master", "Test Change")).get().id;
+
+    setApiUser(admin);
+    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();
@@ -430,6 +441,18 @@
   }
 
   @Test
+  public void setReadyForReviewAllowedAsAdmin() throws Exception {
+    setApiUser(user);
+    String changeId =
+        gApi.changes().create(new ChangeInput(project.get(), "master", "Test Change")).get().id;
+    gApi.changes().id(changeId).setWorkInProgress();
+
+    setApiUser(admin);
+    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();
@@ -675,6 +698,37 @@
   }
 
   @Test
+  public void revertNotifications() throws Exception {
+    PushOneCommit.Result r = createChange();
+    gApi.changes().id(r.getChangeId()).addReviewer(user.email);
+    gApi.changes().id(r.getChangeId()).revision(r.getCommit().name()).review(ReviewInput.approve());
+    gApi.changes().id(r.getChangeId()).revision(r.getCommit().name()).submit();
+
+    sender.clear();
+    ChangeInfo revertChange = gApi.changes().id(r.getChangeId()).revert().get();
+
+    List<Message> messages = sender.getMessages();
+    assertThat(messages).hasSize(2);
+    assertThat(sender.getMessages(revertChange.changeId, "newchange")).hasSize(1);
+    assertThat(sender.getMessages(r.getChangeId(), "revert")).hasSize(1);
+  }
+
+  @Test
+  public void suppressRevertNotifications() throws Exception {
+    PushOneCommit.Result r = createChange();
+    gApi.changes().id(r.getChangeId()).addReviewer(user.email);
+    gApi.changes().id(r.getChangeId()).revision(r.getCommit().name()).review(ReviewInput.approve());
+    gApi.changes().id(r.getChangeId()).revision(r.getCommit().name()).submit();
+
+    RevertInput revertInput = new RevertInput();
+    revertInput.notify = NotifyHandling.NONE;
+
+    sender.clear();
+    gApi.changes().id(r.getChangeId()).revert(revertInput).get();
+    assertThat(sender.getMessages()).isEmpty();
+  }
+
+  @Test
   public void revertPreservesReviewersAndCcs() throws Exception {
     PushOneCommit.Result r = createChange();
 
@@ -789,6 +843,26 @@
   }
 
   @Test
+  public void rebaseOnChangeNumber() throws Exception {
+    String branchTip = testRepo.getRepository().exactRef("HEAD").getObjectId().name();
+    PushOneCommit.Result r1 = createChange();
+    testRepo.reset("HEAD~1");
+    PushOneCommit.Result r2 = createChange();
+
+    ChangeInfo ci2 = get(r2.getChangeId(), CURRENT_REVISION, CURRENT_COMMIT);
+    RevisionInfo ri2 = ci2.revisions.get(ci2.currentRevision);
+    assertThat(ri2.commit.parents.get(0).commit).isEqualTo(branchTip);
+
+    RebaseInput in = new RebaseInput();
+    in.base = Integer.toString(r1.getChange().getId().get());
+    gApi.changes().id(r2.getChangeId()).rebase(in);
+
+    ci2 = get(r2.getChangeId(), CURRENT_REVISION, CURRENT_COMMIT);
+    ri2 = ci2.revisions.get(ci2.currentRevision);
+    assertThat(ri2.commit.parents.get(0).commit).isEqualTo(r1.getCommit().name());
+  }
+
+  @Test
   public void rebaseNotAllowedWithoutPermission() throws Exception {
     // Create two changes both with the same parent
     PushOneCommit.Result r = createChange();
@@ -1506,7 +1580,6 @@
     assertThat(sender.getMessages()).hasSize(1);
   }
 
-  @Ignore
   @Test
   public void addReviewerThatIsNotPerfectMatch() throws Exception {
     TestTimeUtil.resetWithClockStep(1, SECONDS);
@@ -1551,7 +1624,6 @@
     assertThat(rsrc.getChange().getLastUpdatedOn()).isNotEqualTo(oldTs);
   }
 
-  @Ignore
   @Test
   public void addGroupAsReviewersWhenANotPerfectMatchedUserExists() throws Exception {
     TestTimeUtil.resetWithClockStep(1, SECONDS);
@@ -1560,16 +1632,17 @@
     String oldETag = rsrc.getETag();
     Timestamp oldTs = rsrc.getChange().getLastUpdatedOn();
 
-    //create a group named "us" with one user: testUser
-    TestAccount testUser = accountCreator.create("testUser", "testUser@test.com", "testUser");
-    String testGroup =
-        createGroupWithRealName(user.fullName.substring(0, user.fullName.length() / 2));
+    //create a group named "kobe" with one user: lee
+    TestAccount testUser = accountCreator.create("kobebryant", "kobebryant@test.com", "kobebryant");
+    TestAccount myGroupUser = accountCreator.create("lee", "lee@test.com", "lee");
+
+    String testGroup = createGroupWithRealName("kobe");
     GroupApi groupApi = gApi.groups().id(testGroup);
     groupApi.description("test group");
-    groupApi.addMembers(testUser.fullName);
+    groupApi.addMembers(myGroupUser.fullName);
 
     //ensure that user "user" is not in the group
-    groupApi.removeMembers(user.fullName);
+    groupApi.removeMembers(testUser.fullName);
 
     AddReviewerInput in = new AddReviewerInput();
     in.reviewer = testGroup;
@@ -1578,11 +1651,11 @@
     List<Message> messages = sender.getMessages();
     assertThat(messages).hasSize(1);
     Message m = messages.get(0);
-    assertThat(m.rcpt()).containsExactly(testUser.emailAddress);
-    assertThat(m.body()).contains("Hello " + testUser.fullName + ",\n");
+    assertThat(m.rcpt()).containsExactly(myGroupUser.emailAddress);
+    assertThat(m.body()).contains("Hello " + myGroupUser.fullName + ",\n");
     assertThat(m.body()).contains("I'd like you to do a code review.");
     assertThat(m.body()).contains("Change subject: " + PushOneCommit.SUBJECT + "\n");
-    assertMailReplyTo(m, testUser.email);
+    assertMailReplyTo(m, myGroupUser.email);
     ChangeInfo c = gApi.changes().id(r.getChangeId()).get();
 
     // When NoteDb is enabled adding a reviewer records that user as reviewer
@@ -1592,7 +1665,7 @@
     Collection<AccountInfo> reviewers = c.reviewers.get(REVIEWER);
     assertThat(reviewers).isNotNull();
     assertThat(reviewers).hasSize(1);
-    assertThat(reviewers.iterator().next()._accountId).isEqualTo(testUser.getId().get());
+    assertThat(reviewers.iterator().next()._accountId).isEqualTo(myGroupUser.getId().get());
 
     // Ensure ETag and lastUpdatedOn are updated.
     rsrc = parseResource(r);
@@ -2677,7 +2750,7 @@
     gApi.changes().id(changeId).createMergePatchSet(in);
     ChangeInfo changeInfo =
         gApi.changes().id(changeId).get(ALL_REVISIONS, CURRENT_COMMIT, CURRENT_REVISION);
-    assertThat(changeInfo.revisions.size()).isEqualTo(2);
+    assertThat(changeInfo.revisions).hasSize(2);
     assertThat(changeInfo.subject).isEqualTo(in.subject);
     assertThat(changeInfo.revisions.get(changeInfo.currentRevision).commit.parents.get(0).commit)
         .isEqualTo(parent);
@@ -2715,7 +2788,7 @@
     ChangeInfo changeInfo =
         gApi.changes().id(changeId).get(ALL_REVISIONS, CURRENT_COMMIT, CURRENT_REVISION);
 
-    assertThat(changeInfo.revisions.size()).isEqualTo(2);
+    assertThat(changeInfo.revisions).hasSize(2);
     assertThat(changeInfo.subject).isEqualTo(in.subject);
     assertThat(changeInfo.revisions.get(changeInfo.currentRevision).commit.parents.get(0).commit)
         .isEqualTo(parent);
@@ -2770,7 +2843,7 @@
 
     ChangeInfo changeInfo =
         gApi.changes().id(changeId).get(ALL_REVISIONS, CURRENT_COMMIT, CURRENT_REVISION);
-    assertThat(changeInfo.revisions.size()).isEqualTo(2);
+    assertThat(changeInfo.revisions).hasSize(2);
     assertThat(changeInfo.subject).isEqualTo("create ps2");
     assertThat(changeInfo.revisions.get(changeInfo.currentRevision).commit.parents.get(0).commit)
         .isEqualTo(expectedParent);
diff --git a/javatests/com/google/gerrit/acceptance/api/group/GroupRebuilderIT.java b/javatests/com/google/gerrit/acceptance/api/group/GroupRebuilderIT.java
deleted file mode 100644
index bfe01ef..0000000
--- a/javatests/com/google/gerrit/acceptance/api/group/GroupRebuilderIT.java
+++ /dev/null
@@ -1,254 +0,0 @@
-// Copyright (C) 2017 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.api.group;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.TruthJUnit.assume;
-import static com.google.gerrit.extensions.common.testing.CommitInfoSubject.assertThat;
-
-import com.google.common.collect.ImmutableList;
-import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.NoHttpd;
-import com.google.gerrit.acceptance.TestAccount;
-import com.google.gerrit.common.TimeUtil;
-import com.google.gerrit.extensions.common.CommitInfo;
-import com.google.gerrit.extensions.common.GroupInfo;
-import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.reviewdb.client.AccountGroupById;
-import com.google.gerrit.reviewdb.client.AccountGroupByIdAud;
-import com.google.gerrit.reviewdb.client.RefNames;
-import com.google.gerrit.server.ServerInitiated;
-import com.google.gerrit.server.config.GerritServerId;
-import com.google.gerrit.server.git.CommitUtil;
-import com.google.gerrit.server.group.SystemGroupBackend;
-import com.google.gerrit.server.group.db.GroupBundle;
-import com.google.gerrit.server.group.db.GroupRebuilder;
-import com.google.gerrit.server.group.db.GroupsUpdate;
-import com.google.gerrit.server.notedb.GroupsMigration;
-import com.google.gerrit.testing.TestTimeUtil;
-import com.google.gerrit.testing.TestTimeUtil.TempClockStep;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.RefUpdate;
-import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.revwalk.RevCommit;
-import org.eclipse.jgit.revwalk.RevSort;
-import org.eclipse.jgit.revwalk.RevWalk;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-@NoHttpd
-public class GroupRebuilderIT extends AbstractDaemonTest {
-  @Inject @GerritServerId private String serverId;
-  @Inject @ServerInitiated private Provider<GroupsUpdate> groupsUpdate;
-  @Inject private GroupBundle.Factory bundleFactory;
-  @Inject private GroupRebuilder rebuilder;
-  @Inject private GroupsMigration migration;
-
-  @Before
-  public void setUp() {
-    // This test is explicitly testing the migration from ReviewDb to NoteDb, and handles reading
-    // from NoteDb manually. It should work regardless of the value of noteDb.groups.write, however.
-    assume().that(migration.readFromNoteDb()).isFalse();
-  }
-
-  @Before
-  public void setTimeForTesting() {
-    TestTimeUtil.resetWithClockStep(1, TimeUnit.SECONDS);
-  }
-
-  @After
-  public void resetTime() {
-    TestTimeUtil.useSystemTime();
-  }
-
-  @Test
-  public void basicGroupProperties() throws Exception {
-    GroupInfo createdGroup = gApi.groups().create(name("group")).get();
-    try (BlockReviewDbUpdatesForGroups ctx = new BlockReviewDbUpdatesForGroups()) {
-      GroupBundle reviewDbBundle =
-          bundleFactory.fromReviewDb(db, new AccountGroup.Id(createdGroup.groupId));
-      deleteGroupRefs(reviewDbBundle);
-
-      assertMigratedCleanly(rebuild(reviewDbBundle), reviewDbBundle);
-    }
-  }
-
-  @Test
-  public void logFormat() throws Exception {
-    TestAccount user2 = accountCreator.user2();
-    GroupInfo group1 = gApi.groups().create(name("group1")).get();
-    GroupInfo group2 = gApi.groups().create(name("group2")).get();
-
-    try (TempClockStep step = TestTimeUtil.freezeClock()) {
-      gApi.groups().id(group1.id).addMembers(user.id.toString(), user2.id.toString());
-    }
-    TimeUtil.nowTs();
-
-    try (TempClockStep step = TestTimeUtil.freezeClock()) {
-      gApi.groups().id(group1.id).addGroups(group2.id, SystemGroupBackend.REGISTERED_USERS.get());
-    }
-
-    try (BlockReviewDbUpdatesForGroups ctx = new BlockReviewDbUpdatesForGroups()) {
-      GroupBundle reviewDbBundle =
-          bundleFactory.fromReviewDb(db, new AccountGroup.Id(group1.groupId));
-      deleteGroupRefs(reviewDbBundle);
-
-      GroupBundle noteDbBundle = rebuild(reviewDbBundle);
-      assertMigratedCleanly(noteDbBundle, reviewDbBundle);
-
-      ImmutableList<CommitInfo> log = log(group1);
-      assertThat(log).hasSize(4);
-
-      assertThat(log.get(0)).message().isEqualTo("Create group");
-      assertThat(log.get(0)).author().name().isEqualTo(serverIdent.get().getName());
-      assertThat(log.get(0)).author().email().isEqualTo(serverIdent.get().getEmailAddress());
-      assertThat(log.get(0)).author().date().isEqualTo(noteDbBundle.group().getCreatedOn());
-      assertThat(log.get(0)).author().tz().isEqualTo(serverIdent.get().getTimeZoneOffset());
-      assertThat(log.get(0)).committer().isEqualTo(log.get(0).author);
-
-      assertThat(log.get(1))
-          .message()
-          .isEqualTo("Update group\n\nAdd: Administrator <" + admin.id + "@" + serverId + ">");
-      assertThat(log.get(1)).author().name().isEqualTo(admin.fullName);
-      assertThat(log.get(1)).author().email().isEqualTo(admin.id + "@" + serverId);
-      assertThat(log.get(1)).committer().hasSameDateAs(log.get(1).author);
-
-      assertThat(log.get(2))
-          .message()
-          .isEqualTo(
-              "Update group\n"
-                  + "\n"
-                  + ("Add: User <" + user.id + "@" + serverId + ">\n")
-                  + ("Add: User2 <" + user2.id + "@" + serverId + ">"));
-      assertThat(log.get(2)).author().name().isEqualTo(admin.fullName);
-      assertThat(log.get(2)).author().email().isEqualTo(admin.id + "@" + serverId);
-      assertThat(log.get(2)).committer().hasSameDateAs(log.get(2).author);
-
-      assertThat(log.get(3))
-          .message()
-          .isEqualTo(
-              "Update group\n"
-                  + "\n"
-                  + ("Add-group: " + group2.name + " <" + group2.id + ">\n")
-                  + ("Add-group: Registered Users <global:Registered-Users>"));
-      assertThat(log.get(3)).author().name().isEqualTo(admin.fullName);
-      assertThat(log.get(3)).author().email().isEqualTo(admin.id + "@" + serverId);
-      assertThat(log.get(3)).committer().hasSameDateAs(log.get(3).author);
-    }
-  }
-
-  @Test
-  public void unknownGroupUuid() throws Exception {
-    GroupInfo group = gApi.groups().create(name("group")).get();
-
-    AccountGroup.UUID subgroupUuid = new AccountGroup.UUID("mybackend:foo");
-
-    AccountGroupById byId =
-        new AccountGroupById(
-            new AccountGroupById.Key(new AccountGroup.Id(group.groupId), subgroupUuid));
-    assertThat(groupBackend.handles(byId.getIncludeUUID())).isFalse();
-    db.accountGroupById().insert(Collections.singleton(byId));
-
-    AccountGroupByIdAud audit = new AccountGroupByIdAud(byId, admin.id, TimeUtil.nowTs());
-    db.accountGroupByIdAud().insert(Collections.singleton(audit));
-
-    GroupBundle reviewDbBundle = bundleFactory.fromReviewDb(db, new AccountGroup.Id(group.groupId));
-    deleteGroupRefs(reviewDbBundle);
-
-    GroupBundle noteDbBundle = rebuild(reviewDbBundle);
-    assertMigratedCleanly(noteDbBundle, reviewDbBundle);
-
-    ImmutableList<CommitInfo> log = log(group);
-    assertThat(log).hasSize(3);
-
-    assertThat(log.get(0)).message().isEqualTo("Create group");
-    assertThat(log.get(1))
-        .message()
-        .isEqualTo("Update group\n\nAdd: Administrator <" + admin.id + "@" + serverId + ">");
-    assertThat(log.get(2))
-        .message()
-        .isEqualTo("Update group\n\nAdd-group: mybackend:foo <mybackend:foo>");
-  }
-
-  private void deleteGroupRefs(GroupBundle bundle) throws Exception {
-    try (Repository repo = repoManager.openRepository(allUsers)) {
-      String refName = RefNames.refsGroups(bundle.uuid());
-      RefUpdate ru = repo.updateRef(refName);
-      ru.setForceUpdate(true);
-      Ref oldRef = repo.exactRef(refName);
-      if (oldRef == null) {
-        return;
-      }
-      ru.setExpectedOldObjectId(oldRef.getObjectId());
-      ru.setNewObjectId(ObjectId.zeroId());
-      assertThat(ru.delete()).isEqualTo(RefUpdate.Result.FORCED);
-    }
-  }
-
-  private GroupBundle rebuild(GroupBundle reviewDbBundle) throws Exception {
-    try (Repository repo = repoManager.openRepository(allUsers)) {
-      rebuilder.rebuild(repo, reviewDbBundle, null);
-      return bundleFactory.fromNoteDb(repo, reviewDbBundle.uuid());
-    }
-  }
-
-  private void assertMigratedCleanly(GroupBundle noteDbBundle, GroupBundle expectedReviewDbBundle) {
-    assertThat(GroupBundle.compareWithAudits(expectedReviewDbBundle, noteDbBundle)).isEmpty();
-  }
-
-  private ImmutableList<CommitInfo> log(GroupInfo g) throws Exception {
-    ImmutableList.Builder<CommitInfo> result = ImmutableList.builder();
-    List<Date> commitDates = new ArrayList<>();
-    try (Repository repo = repoManager.openRepository(allUsers);
-        RevWalk rw = new RevWalk(repo)) {
-      Ref ref = repo.exactRef(RefNames.refsGroups(new AccountGroup.UUID(g.id)));
-      if (ref != null) {
-        rw.sort(RevSort.REVERSE);
-        rw.setRetainBody(true);
-        rw.markStart(rw.parseCommit(ref.getObjectId()));
-        for (RevCommit c : rw) {
-          result.add(CommitUtil.toCommitInfo(c));
-          commitDates.add(c.getCommitterIdent().getWhen());
-        }
-      }
-    }
-    assertThat(commitDates).named("commit timestamps for %s", result).isOrdered();
-    return result.build();
-  }
-
-  private class BlockReviewDbUpdatesForGroups implements AutoCloseable {
-    BlockReviewDbUpdatesForGroups() {
-      blockReviewDbUpdates(true);
-    }
-
-    @Override
-    public void close() throws Exception {
-      blockReviewDbUpdates(false);
-    }
-
-    private void blockReviewDbUpdates(boolean block) {
-      cfg.setBoolean("user", null, "blockReviewDbGroupUpdates", block);
-    }
-  }
-}
diff --git a/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java b/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java
index 32dc5dd..0e5da12 100644
--- a/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java
@@ -32,7 +32,6 @@
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 import static java.util.stream.Collectors.toList;
 
-import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import com.google.common.util.concurrent.AtomicLongMap;
@@ -66,7 +65,6 @@
 import com.google.gerrit.extensions.restapi.BadRequestException;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
-import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
 import com.google.gerrit.extensions.restapi.Url;
 import com.google.gerrit.reviewdb.client.Account;
@@ -89,7 +87,6 @@
 import com.google.gerrit.server.util.MagicBranch;
 import com.google.gerrit.testing.ConfigSuite;
 import com.google.gerrit.testing.TestTimeUtil;
-import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import java.io.IOException;
 import java.lang.annotation.Retention;
@@ -280,7 +277,7 @@
 
     List<? extends GroupAuditEventInfo> auditEvents = gApi.groups().id(g).auditLog();
     assertThat(auditEvents).hasSize(1);
-    assertAuditEvent(auditEvents.get(0), Type.ADD_GROUP, admin.id, "Registered Users");
+    assertSubgroupAuditEvent(auditEvents.get(0), Type.ADD_GROUP, admin.id, "Registered Users");
   }
 
   @Test
@@ -857,41 +854,41 @@
     GroupApi g = gApi.groups().create(name("group"));
     List<? extends GroupAuditEventInfo> auditEvents = g.auditLog();
     assertThat(auditEvents).hasSize(1);
-    assertAuditEvent(auditEvents.get(0), Type.ADD_USER, admin.id, admin.id);
+    assertMemberAuditEvent(auditEvents.get(0), Type.ADD_USER, admin.id, admin.id);
 
     g.addMembers(user.username);
     auditEvents = g.auditLog();
     assertThat(auditEvents).hasSize(2);
-    assertAuditEvent(auditEvents.get(0), Type.ADD_USER, admin.id, user.id);
+    assertMemberAuditEvent(auditEvents.get(0), Type.ADD_USER, admin.id, user.id);
 
     g.removeMembers(user.username);
     auditEvents = g.auditLog();
     assertThat(auditEvents).hasSize(3);
-    assertAuditEvent(auditEvents.get(0), Type.REMOVE_USER, admin.id, user.id);
+    assertMemberAuditEvent(auditEvents.get(0), Type.REMOVE_USER, admin.id, user.id);
 
     String otherGroup = name("otherGroup");
     gApi.groups().create(otherGroup);
     g.addGroups(otherGroup);
     auditEvents = g.auditLog();
     assertThat(auditEvents).hasSize(4);
-    assertAuditEvent(auditEvents.get(0), Type.ADD_GROUP, admin.id, otherGroup);
+    assertSubgroupAuditEvent(auditEvents.get(0), Type.ADD_GROUP, admin.id, otherGroup);
 
     g.removeGroups(otherGroup);
     auditEvents = g.auditLog();
     assertThat(auditEvents).hasSize(5);
-    assertAuditEvent(auditEvents.get(0), Type.REMOVE_GROUP, admin.id, otherGroup);
+    assertSubgroupAuditEvent(auditEvents.get(0), Type.REMOVE_GROUP, admin.id, otherGroup);
 
     // Add a removed member back again.
     g.addMembers(user.username);
     auditEvents = g.auditLog();
     assertThat(auditEvents).hasSize(6);
-    assertAuditEvent(auditEvents.get(0), Type.ADD_USER, admin.id, user.id);
+    assertMemberAuditEvent(auditEvents.get(0), Type.ADD_USER, admin.id, user.id);
 
     // Add a removed group back again.
     g.addGroups(otherGroup);
     auditEvents = g.auditLog();
     assertThat(auditEvents).hasSize(7);
-    assertAuditEvent(auditEvents.get(0), Type.ADD_GROUP, admin.id, otherGroup);
+    assertSubgroupAuditEvent(auditEvents.get(0), Type.ADD_GROUP, admin.id, otherGroup);
 
     Timestamp lastDate = null;
     for (GroupAuditEventInfo auditEvent : auditEvents) {
@@ -902,6 +899,52 @@
     }
   }
 
+  /**
+   * @Sandboxed is used by this test because it deletes a group reference which introduces an
+   * inconsistency for the group storage. Once group deletion is supported, this test should be
+   * updated to use the API instead.
+   */
+  @Test
+  @Sandboxed
+  @IgnoreGroupInconsistencies
+  public void getAuditLogAfterDeletingASubgroup() throws Exception {
+    assume().that(readGroupsFromNoteDb()).isTrue();
+
+    GroupInfo parentGroup = gApi.groups().create(name("parent-group")).get();
+
+    // Creates a subgroup and adds it to "parent-group" as a subgroup.
+    GroupInfo subgroup = gApi.groups().create(name("sub-group")).get();
+    gApi.groups().id(parentGroup.id).addGroups(subgroup.id);
+
+    // Deletes the subgroup.
+    deleteGroupRef(subgroup.id);
+
+    List<? extends GroupAuditEventInfo> auditEvents = gApi.groups().id(parentGroup.id).auditLog();
+    assertThat(auditEvents).hasSize(2);
+    // Verify the unavailable subgroup's name is null.
+    assertSubgroupAuditEvent(auditEvents.get(0), Type.ADD_GROUP, admin.id, null);
+  }
+
+  private void deleteGroupRef(String groupId) throws Exception {
+    AccountGroup.UUID uuid = new AccountGroup.UUID(groupId);
+    try (Repository repo = repoManager.openRepository(allUsers)) {
+      RefUpdate ru = repo.updateRef(RefNames.refsGroups(uuid));
+      ru.setForceUpdate(true);
+      ru.setNewObjectId(ObjectId.zeroId());
+      assertThat(ru.delete()).isEqualTo(RefUpdate.Result.FORCED);
+    }
+
+    // Reindex the group.
+    gApi.groups().id(uuid.get()).index();
+
+    // Verify "sub-group" has been deleted.
+    try {
+      gApi.groups().id(uuid.get()).get();
+      fail();
+    } catch (ResourceNotFoundException e) {
+    }
+  }
+
   // reindex is tested by {@link AbstractQueryGroupsTest#reindex}
   @Test
   public void reindexPermissions() throws Exception {
@@ -1154,38 +1197,6 @@
   }
 
   @Test
-  @Sandboxed
-  public void blockReviewDbUpdatesOnGroupCreation() throws Exception {
-    assume().that(groupsInNoteDb()).isFalse();
-    try (AutoCloseable ctx = createBlockReviewDbGroupUpdatesContext()) {
-      gApi.groups().create(name("foo"));
-      fail("Expected RestApiException: Updates to groups in ReviewDb are blocked");
-    } catch (RestApiException e) {
-      assertWriteGroupToReviewDbBlockedException(e);
-    }
-  }
-
-  @Test
-  @Sandboxed
-  public void blockReviewDbUpdatesOnGroupUpdate() throws Exception {
-    assume().that(groupsInNoteDb()).isFalse();
-    String group1 = gApi.groups().create(name("foo")).get().id;
-    String group2 = gApi.groups().create(name("bar")).get().id;
-    try (AutoCloseable ctx = createBlockReviewDbGroupUpdatesContext()) {
-      gApi.groups().id(group1).addGroups(group2);
-      fail("Expected RestApiException: Updates to groups in ReviewDb are blocked");
-    } catch (RestApiException e) {
-      assertWriteGroupToReviewDbBlockedException(e);
-    }
-  }
-
-  private void assertWriteGroupToReviewDbBlockedException(Exception e) throws Exception {
-    Throwable t = Throwables.getRootCause(e);
-    assertThat(t).isInstanceOf(OrmException.class);
-    assertThat(t.getMessage()).isEqualTo("Updates to groups in ReviewDb are blocked");
-  }
-
-  @Test
   @IgnoreGroupInconsistencies
   public void stalenessChecker() throws Exception {
     assume().that(readGroupsFromNoteDb()).isTrue();
@@ -1411,7 +1422,7 @@
     }
   }
 
-  private void assertAuditEvent(
+  private void assertMemberAuditEvent(
       GroupAuditEventInfo info,
       Type expectedType,
       Account.Id expectedUser,
@@ -1422,7 +1433,7 @@
     assertThat(((UserMemberAuditEventInfo) info).member._accountId).isEqualTo(expectedMember.get());
   }
 
-  private void assertAuditEvent(
+  private void assertSubgroupAuditEvent(
       GroupAuditEventInfo info,
       Type expectedType,
       Account.Id expectedUser,
@@ -1481,16 +1492,6 @@
     return groupsInNoteDb() && cfg.getBoolean(SECTION_NOTE_DB, GROUPS.key(), READ, false);
   }
 
-  private AutoCloseable createBlockReviewDbGroupUpdatesContext() {
-    cfg.setBoolean("user", null, "blockReviewDbGroupUpdates", true);
-    return new AutoCloseable() {
-      @Override
-      public void close() {
-        cfg.setBoolean("user", null, "blockReviewDbGroupUpdates", false);
-      }
-    };
-  }
-
   @Target({METHOD})
   @Retention(RUNTIME)
   private @interface IgnoreGroupInconsistencies {}
diff --git a/javatests/com/google/gerrit/acceptance/api/project/DashboardIT.java b/javatests/com/google/gerrit/acceptance/api/project/DashboardIT.java
index 37a86d2..e51a069 100644
--- a/javatests/com/google/gerrit/acceptance/api/project/DashboardIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/project/DashboardIT.java
@@ -150,7 +150,7 @@
     if (expected.sections == null) {
       assertThat(actual.sections).isNull();
     } else {
-      assertThat(actual.sections.size()).isEqualTo(expected.sections.size());
+      assertThat(actual.sections).hasSize(expected.sections.size());
     }
   }
 
diff --git a/javatests/com/google/gerrit/acceptance/api/project/ProjectIT.java b/javatests/com/google/gerrit/acceptance/api/project/ProjectIT.java
index c986c5e..84cfb0d 100644
--- a/javatests/com/google/gerrit/acceptance/api/project/ProjectIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/project/ProjectIT.java
@@ -158,6 +158,38 @@
   }
 
   @Test
+  public void createProjectWithNonExistingParent() throws Exception {
+    ProjectInput in = new ProjectInput();
+    in.name = name("baz");
+    in.parent = "non-existing";
+
+    exception.expect(UnprocessableEntityException.class);
+    exception.expectMessage("Project Not Found: " + in.parent);
+    gApi.projects().create(in);
+  }
+
+  @Test
+  public void createProjectWithSelfAsParentNotPossible() throws Exception {
+    ProjectInput in = new ProjectInput();
+    in.name = name("baz");
+    in.parent = in.name;
+
+    exception.expect(UnprocessableEntityException.class);
+    exception.expectMessage("Project Not Found: " + in.parent);
+    gApi.projects().create(in);
+  }
+
+  @Test
+  public void createProjectUnderAllUsersNotAllowed() throws Exception {
+    ProjectInput in = new ProjectInput();
+    in.name = name("foo");
+    in.parent = allUsers.get();
+    exception.expect(ResourceConflictException.class);
+    exception.expectMessage(String.format("Cannot inherit from '%s' project", allUsers.get()));
+    gApi.projects().create(in);
+  }
+
+  @Test
   public void createAndDeleteBranch() throws Exception {
     assertThat(getRemoteHead(project.get(), "foo")).isNull();
 
diff --git a/javatests/com/google/gerrit/acceptance/api/project/SetParentIT.java b/javatests/com/google/gerrit/acceptance/api/project/SetParentIT.java
index c1bc83e..ec4f327 100644
--- a/javatests/com/google/gerrit/acceptance/api/project/SetParentIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/project/SetParentIT.java
@@ -90,6 +90,13 @@
   }
 
   @Test
+  public void setParentToAllUsersNotAllowed() throws Exception {
+    exception.expect(ResourceConflictException.class);
+    exception.expectMessage(String.format("Cannot inherit from '%s' project", allUsers.get()));
+    gApi.projects().name(project.get()).parent(allUsers.get());
+  }
+
+  @Test
   public void setParentForAllUsersMustBeAllProjects() throws Exception {
     gApi.projects().name(allUsers.get()).parent(allProjects.get());
 
diff --git a/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java b/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java
index 7583830..2812c86 100644
--- a/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java
+++ b/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java
@@ -346,17 +346,17 @@
           "master",
           "Update git submodules\n\n"
               + "* Update "
-              + name("sub3")
+              + name("sub1")
               + " from branch 'master'\n  to "
-              + sub3HEAD
+              + sub1HEAD
               + "\n\n* Update "
               + name("sub2")
               + " from branch 'master'\n  to "
               + sub2HEAD
               + "\n\n* Update "
-              + name("sub1")
+              + name("sub3")
               + " from branch 'master'\n  to "
-              + sub1HEAD);
+              + sub3HEAD);
     }
 
     superRepo
diff --git a/javatests/com/google/gerrit/acceptance/rest/group/GroupsIT.java b/javatests/com/google/gerrit/acceptance/rest/group/GroupsIT.java
index a52dd6d..e153e561 100644
--- a/javatests/com/google/gerrit/acceptance/rest/group/GroupsIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/group/GroupsIT.java
@@ -15,27 +15,12 @@
 package com.google.gerrit.acceptance.rest.group;
 
 import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.TruthJUnit.assume;
 
 import com.google.gerrit.acceptance.AbstractDaemonTest;
 import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.extensions.common.GroupInfo;
-import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.reviewdb.client.RefNames;
-import com.google.gerrit.server.group.db.GroupBundle;
-import com.google.gerrit.server.notedb.GroupsMigration;
-import com.google.gerrit.server.restapi.group.Rebuild;
-import com.google.inject.Inject;
-import org.eclipse.jgit.junit.TestRepository;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.Repository;
 import org.junit.Test;
 
 public class GroupsIT extends AbstractDaemonTest {
-  @Inject private GroupsMigration groupsMigration;
-  @Inject private GroupBundle.Factory bundleFactory;
-
   @Test
   public void invalidQueryOptions() throws Exception {
     RestResponse r = adminRestSession.put("/groups/?query=foo&query2=bar");
@@ -43,138 +28,4 @@
     assertThat(r.getEntityContent())
         .isEqualTo("\"query\" and \"query2\" options are mutually exclusive");
   }
-
-  @Test
-  public void rebuild() throws Exception {
-    assume().that(groupsMigration.writeToNoteDb()).isTrue();
-    assume().that(groupsMigration.readFromNoteDb()).isFalse();
-
-    GroupInfo g = gApi.groups().create(name("group")).get();
-    AccountGroup.UUID uuid = new AccountGroup.UUID(g.id);
-    String refName = RefNames.refsGroups(uuid);
-    ObjectId oldId;
-    GroupBundle oldBundle;
-    try (Repository repo = repoManager.openRepository(allUsers)) {
-      oldId = repo.exactRef(refName).getObjectId();
-      oldBundle = bundleFactory.fromNoteDb(repo, uuid);
-      new TestRepository<>(repo).delete(refName);
-    }
-
-    assertThat(
-            adminRestSession.postOK("/groups/" + uuid + "/rebuild", input(null)).getEntityContent())
-        .isEqualTo("No differences between ReviewDb and NoteDb");
-
-    try (Repository repo = repoManager.openRepository(allUsers)) {
-      Ref ref = repo.exactRef(refName);
-      assertThat(ref).isNotNull();
-
-      // An artifact of the migration process makes the SHA-1 different, but it's actually ok
-      // because the bundles are equal.
-      assertThat(ref.getObjectId()).isNotEqualTo(oldId);
-
-      assertNoDifferences(oldBundle, bundleFactory.fromNoteDb(repo, uuid));
-    }
-  }
-
-  @Test
-  public void rebuildFailsWithWritesDisabled() throws Exception {
-    assume().that(groupsMigration.writeToNoteDb()).isFalse();
-
-    GroupInfo g = gApi.groups().create(name("group")).get();
-    AccountGroup.UUID uuid = new AccountGroup.UUID(g.id);
-
-    RestResponse res = adminRestSession.post("/groups/" + uuid + "/rebuild", input(null));
-    assertThat(res.getStatusCode()).isEqualTo(405);
-    assertThat(res.getEntityContent()).isEqualTo("NoteDb writes must be enabled");
-  }
-
-  @Test
-  public void rebuildForceRequiresReadsDisabled() throws Exception {
-    assume().that(groupsMigration.writeToNoteDb()).isTrue();
-    assume().that(groupsMigration.readFromNoteDb()).isTrue();
-
-    GroupInfo g = gApi.groups().create(name("group")).get();
-    AccountGroup.UUID uuid = new AccountGroup.UUID(g.id);
-
-    RestResponse res = adminRestSession.post("/groups/" + uuid + "/rebuild", input(true));
-    assertThat(res.getStatusCode()).isEqualTo(405);
-    assertThat(res.getEntityContent())
-        .isEqualTo("NoteDb reads must not be enabled when force=true");
-  }
-
-  @Test
-  public void rebuildWithoutForceFailsIfRefExists() throws Exception {
-    assume().that(groupsMigration.writeToNoteDb()).isTrue();
-    assume().that(groupsMigration.readFromNoteDb()).isFalse();
-
-    GroupInfo g = gApi.groups().create(name("group")).get();
-    AccountGroup.UUID uuid = new AccountGroup.UUID(g.id);
-    String refName = RefNames.refsGroups(uuid);
-
-    try (Repository repo = repoManager.openRepository(allUsers)) {
-      new TestRepository<>(repo)
-          .branch(refName)
-          .commit()
-          .add("somefile", "contents")
-          .create()
-          .copy();
-    }
-
-    RestResponse res = adminRestSession.post("/groups/" + uuid + "/rebuild", input(null));
-    assertThat(res.getStatusCode()).isEqualTo(409);
-    assertThat(res.getEntityContent()).isEqualTo("Group already exists in NoteDb");
-  }
-
-  @Test
-  public void rebuildForce() throws Exception {
-    assume().that(groupsMigration.writeToNoteDb()).isTrue();
-    assume().that(groupsMigration.readFromNoteDb()).isFalse();
-
-    GroupInfo g = gApi.groups().create(name("group")).get();
-    AccountGroup.UUID uuid = new AccountGroup.UUID(g.id);
-    String refName = RefNames.refsGroups(uuid);
-
-    ObjectId oldId;
-    GroupBundle oldBundle;
-    try (Repository repo = repoManager.openRepository(allUsers)) {
-      oldBundle = bundleFactory.fromNoteDb(repo, uuid);
-
-      oldId =
-          new TestRepository<>(repo)
-              .branch(refName)
-              .commit()
-              .add("somefile", "contents")
-              .create()
-              .copy();
-    }
-
-    assertThat(
-            adminRestSession.postOK("/groups/" + uuid + "/rebuild", input(true)).getEntityContent())
-        .isEqualTo("No differences between ReviewDb and NoteDb");
-
-    try (Repository repo = repoManager.openRepository(allUsers)) {
-      Ref ref = repo.exactRef(refName);
-      assertThat(ref).isNotNull();
-
-      // oldId contains some garbage, so rebuilt value should definitely be different.
-      assertThat(ref.getObjectId()).isNotEqualTo(oldId);
-
-      assertNoDifferences(oldBundle, bundleFactory.fromNoteDb(repo, uuid));
-    }
-  }
-
-  private static void assertNoDifferences(GroupBundle expected, GroupBundle actual) {
-    // Comparing NoteDb to NoteDb, so compare fields instead of using static compare method.
-    assertThat(actual.group()).isEqualTo(expected.group());
-    assertThat(actual.members()).isEqualTo(expected.members());
-    assertThat(actual.memberAudit()).isEqualTo(expected.memberAudit());
-    assertThat(actual.byId()).isEqualTo(expected.byId());
-    assertThat(actual.byIdAudit()).isEqualTo(expected.byIdAudit());
-  }
-
-  private static Rebuild.Input input(Boolean force) {
-    Rebuild.Input input = new Rebuild.Input();
-    input.force = force;
-    return input;
-  }
 }
diff --git a/javatests/com/google/gerrit/acceptance/rest/project/ProjectLevelConfigIT.java b/javatests/com/google/gerrit/acceptance/rest/project/ProjectLevelConfigIT.java
index c1bbf2e..c78b47b 100644
--- a/javatests/com/google/gerrit/acceptance/rest/project/ProjectLevelConfigIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/project/ProjectLevelConfigIT.java
@@ -22,6 +22,7 @@
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.client.RefNames;
 import com.google.gerrit.server.project.ProjectState;
+import java.util.Arrays;
 import org.eclipse.jgit.junit.TestRepository;
 import org.eclipse.jgit.lib.Config;
 import org.junit.Before;
@@ -114,4 +115,67 @@
 
     assertThat(state.getConfig(configName).get().toText()).isEqualTo(cfg.toText());
   }
+
+  @Test
+  public void withMergedInheritance() throws Exception {
+    String configName = "test.config";
+
+    Config parentCfg = new Config();
+    parentCfg.setString("s1", null, "k1", "parentValue1");
+    parentCfg.setString("s1", null, "k2", "parentValue2");
+    parentCfg.setString("s2", "ss", "k3", "parentValue3");
+    parentCfg.setString("s2", "ss", "k4", "parentValue4");
+
+    pushFactory
+        .create(
+            db,
+            admin.getIdent(),
+            testRepo,
+            "Create Project Level Config",
+            configName,
+            parentCfg.toText())
+        .to(RefNames.REFS_CONFIG)
+        .assertOkStatus();
+
+    Project.NameKey childProject = createProject("child", project);
+    TestRepository<?> childTestRepo = cloneProject(childProject);
+    fetch(childTestRepo, RefNames.REFS_CONFIG + ":refs/heads/config");
+    childTestRepo.reset("refs/heads/config");
+
+    Config cfg = new Config();
+    cfg.setString("s1", null, "k1", "parentValue1");
+    cfg.setString("s1", null, "k2", "parentValue2");
+    cfg.setString("s2", "ss", "k3", "parentValue3");
+    cfg.setString("s2", "ss", "k4", "parentValue4");
+    cfg.setString("s1", null, "k1", "childValue1");
+    cfg.setString("s2", "ss", "k3", "childValue2");
+    cfg.setString("s3", null, "k5", "childValue3");
+    cfg.setString("s3", "ss", "k6", "childValue4");
+
+    pushFactory
+        .create(
+            db,
+            admin.getIdent(),
+            childTestRepo,
+            "Create Project Level Config",
+            configName,
+            cfg.toText())
+        .to(RefNames.REFS_CONFIG)
+        .assertOkStatus();
+
+    ProjectState state = projectCache.get(childProject);
+
+    Config expectedCfg = new Config();
+    expectedCfg.setStringList("s1", null, "k1", Arrays.asList("childValue1", "parentValue1"));
+    expectedCfg.setString("s1", null, "k2", "parentValue2");
+    expectedCfg.setStringList("s2", "ss", "k3", Arrays.asList("childValue2", "parentValue3"));
+    expectedCfg.setString("s2", "ss", "k4", "parentValue4");
+    expectedCfg.setString("s3", null, "k5", "childValue3");
+    expectedCfg.setString("s3", "ss", "k6", "childValue4");
+
+    assertThat(state.getConfig(configName).getWithInheritance(true).toText())
+        .isEqualTo(expectedCfg.toText());
+
+    assertThat(state.getConfig(configName).get().toText()).isEqualTo(cfg.toText());
+  }
 }
diff --git a/javatests/com/google/gerrit/acceptance/server/change/CommentsIT.java b/javatests/com/google/gerrit/acceptance/server/change/CommentsIT.java
index 343eacc..e53b997 100644
--- a/javatests/com/google/gerrit/acceptance/server/change/CommentsIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/change/CommentsIT.java
@@ -772,7 +772,7 @@
     Map<String, List<CommentInfo>> commentsMap =
         getPublishedComments(result.getChangeId(), result.getCommit().name());
 
-    assertThat(commentsMap.size()).isEqualTo(1);
+    assertThat(commentsMap).hasSize(1);
     assertThat(commentsMap.get(FILE_NAME)).hasSize(1);
 
     String uuid = commentsMap.get(targetComment.path).get(0).id;
diff --git a/javatests/com/google/gerrit/acceptance/server/change/GetRelatedIT.java b/javatests/com/google/gerrit/acceptance/server/change/GetRelatedIT.java
index 3877239..70ca5f5 100644
--- a/javatests/com/google/gerrit/acceptance/server/change/GetRelatedIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/change/GetRelatedIT.java
@@ -571,8 +571,8 @@
     }
 
     ChangeData cd = getChange(last);
-    assertThat(cd.patchSets().size()).isEqualTo(n);
-    assertThat(GetRelated.getAllGroups(cd.notes(), db, psUtil).size()).isEqualTo(n);
+    assertThat(cd.patchSets()).hasSize(n);
+    assertThat(GetRelated.getAllGroups(cd.notes(), db, psUtil)).hasSize(n);
 
     assertRelated(cd.change().currentPatchSetId());
   }
diff --git a/javatests/com/google/gerrit/acceptance/server/mail/ChangeNotificationsIT.java b/javatests/com/google/gerrit/acceptance/server/mail/ChangeNotificationsIT.java
index 417c9e3..a6c1153 100644
--- a/javatests/com/google/gerrit/acceptance/server/mail/ChangeNotificationsIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/mail/ChangeNotificationsIT.java
@@ -2219,17 +2219,22 @@
     assume().that(notesMigration.readChanges()).isFalse();
     StagedChange sc = stageChange();
     revert(sc, sc.owner);
+
+    // email for the newly created revert change
     assertThat(sender)
         .sent("newchange", sc)
         .to(sc.reviewer, sc.ccer, sc.watchingProjectOwner, admin)
         .bcc(NEW_CHANGES, NEW_PATCHSETS)
-        .noOneElse(); // TODO(logan): Why not starrer/reviewers-by-email?
+        .noOneElse();
 
+    // email for the change that is reverted
     assertThat(sender)
         .sent("revert", sc)
         .cc(sc.reviewer, sc.ccer, admin)
+        .cc(sc.reviewerByEmail)
+        .bcc(sc.starrer)
         .bcc(ALL_COMMENTS)
-        .noOneElse(); // TODO(logan): Why not starrer/reviewers-by-email?
+        .noOneElse();
   }
 
   @Test
@@ -2237,18 +2242,23 @@
     assume().that(notesMigration.readChanges()).isTrue();
     StagedChange sc = stageChange();
     revert(sc, sc.owner);
+
+    // email for the newly created revert change
     assertThat(sender)
         .sent("newchange", sc)
         .to(sc.reviewer, sc.watchingProjectOwner, admin)
         .cc(sc.ccer)
         .bcc(NEW_CHANGES, NEW_PATCHSETS)
-        .noOneElse(); // TODO(logan): Why not starrer/reviewers-by-email?
+        .noOneElse();
 
+    // email for the change that is reverted
     assertThat(sender)
         .sent("revert", sc)
         .cc(sc.reviewer, sc.ccer, admin)
+        .cc(sc.reviewerByEmail, sc.ccerByEmail)
+        .bcc(sc.starrer)
         .bcc(ALL_COMMENTS)
-        .noOneElse(); // TODO(logan): Why not starrer/reviewers-by-email?
+        .noOneElse();
   }
 
   @Test
@@ -2256,19 +2266,24 @@
     assume().that(notesMigration.readChanges()).isFalse();
     StagedChange sc = stageChange();
     revert(sc, sc.owner, CC_ON_OWN_COMMENTS);
+
+    // email for the newly created revert change
     assertThat(sender)
         .sent("newchange", sc)
         .to(sc.reviewer, sc.ccer, sc.watchingProjectOwner, admin)
         .cc(sc.owner)
         .bcc(NEW_CHANGES, NEW_PATCHSETS)
-        .noOneElse(); // TODO(logan): Why not starrer/reviewers-by-email?
+        .noOneElse();
 
+    // email for the change that is reverted
     assertThat(sender)
         .sent("revert", sc)
         .to(sc.owner)
         .cc(sc.reviewer, sc.ccer, admin)
+        .cc(sc.reviewerByEmail)
+        .bcc(sc.starrer)
         .bcc(ALL_COMMENTS)
-        .noOneElse(); // TODO(logan): Why not starrer/reviewers-by-email?
+        .noOneElse();
   }
 
   @Test
@@ -2276,19 +2291,24 @@
     assume().that(notesMigration.readChanges()).isTrue();
     StagedChange sc = stageChange();
     revert(sc, sc.owner, CC_ON_OWN_COMMENTS);
+
+    // email for the newly created revert change
     assertThat(sender)
         .sent("newchange", sc)
         .to(sc.reviewer, sc.watchingProjectOwner, admin)
         .cc(sc.owner, sc.ccer)
         .bcc(NEW_CHANGES, NEW_PATCHSETS)
-        .noOneElse(); // TODO(logan): Why not starrer/reviewers-by-email?
+        .noOneElse();
 
+    // email for the change that is reverted
     assertThat(sender)
         .sent("revert", sc)
         .to(sc.owner)
         .cc(sc.reviewer, sc.ccer, admin)
+        .cc(sc.reviewerByEmail, sc.ccerByEmail)
+        .bcc(sc.starrer)
         .bcc(ALL_COMMENTS)
-        .noOneElse(); // TODO(logan): Why not starrer/reviewers-by-email?
+        .noOneElse();
   }
 
   @Test
@@ -2296,17 +2316,23 @@
     assume().that(notesMigration.readChanges()).isFalse();
     StagedChange sc = stageChange();
     revert(sc, other);
+
+    // email for the newly created revert change
     assertThat(sender)
         .sent("newchange", sc)
         .to(sc.owner, sc.reviewer, sc.ccer, sc.watchingProjectOwner, admin)
         .bcc(NEW_CHANGES, NEW_PATCHSETS)
-        .noOneElse(); // TODO(logan): Why not starrer/reviewers-by-email?
+        .noOneElse();
 
+    // email for the change that is reverted
     assertThat(sender)
         .sent("revert", sc)
-        .cc(sc.owner, sc.reviewer, sc.ccer, admin)
+        .to(sc.owner)
+        .cc(sc.reviewer, sc.ccer, admin)
+        .cc(sc.reviewerByEmail)
+        .bcc(sc.starrer)
         .bcc(ALL_COMMENTS)
-        .noOneElse(); // TODO(logan): Why not starrer/reviewers-by-email?
+        .noOneElse();
   }
 
   @Test
@@ -2314,18 +2340,24 @@
     assume().that(notesMigration.readChanges()).isTrue();
     StagedChange sc = stageChange();
     revert(sc, other);
+
+    // email for the newly created revert change
     assertThat(sender)
         .sent("newchange", sc)
         .to(sc.owner, sc.reviewer, sc.watchingProjectOwner, admin)
         .cc(sc.ccer)
         .bcc(NEW_CHANGES, NEW_PATCHSETS)
-        .noOneElse(); // TODO(logan): Why not starrer/reviewers-by-email?
+        .noOneElse();
 
+    // email for the change that is reverted
     assertThat(sender)
         .sent("revert", sc)
-        .cc(sc.owner, sc.reviewer, sc.ccer, admin)
+        .to(sc.owner)
+        .cc(sc.reviewer, sc.ccer, admin)
+        .cc(sc.reviewerByEmail, sc.ccerByEmail)
+        .bcc(sc.starrer)
         .bcc(ALL_COMMENTS)
-        .noOneElse(); // TODO(logan): Why not starrer/reviewers-by-email?
+        .noOneElse();
   }
 
   @Test
@@ -2333,19 +2365,24 @@
     assume().that(notesMigration.readChanges()).isFalse();
     StagedChange sc = stageChange();
     revert(sc, other, CC_ON_OWN_COMMENTS);
+
+    // email for the newly created revert change
     assertThat(sender)
         .sent("newchange", sc)
         .to(sc.owner, sc.reviewer, sc.ccer, sc.watchingProjectOwner, admin)
         .cc(other)
         .bcc(NEW_CHANGES, NEW_PATCHSETS)
-        .noOneElse(); // TODO(logan): Why not starrer/reviewers-by-email?
+        .noOneElse();
 
+    // email for the change that is reverted
     assertThat(sender)
         .sent("revert", sc)
-        .to(other)
-        .cc(sc.owner, sc.reviewer, sc.ccer, admin)
+        .to(sc.owner)
+        .cc(other, sc.reviewer, sc.ccer, admin)
+        .cc(sc.reviewerByEmail)
+        .bcc(sc.starrer)
         .bcc(ALL_COMMENTS)
-        .noOneElse(); // TODO(logan): Why not starrer/reviewers-by-email?
+        .noOneElse();
   }
 
   @Test
@@ -2353,19 +2390,24 @@
     assume().that(notesMigration.readChanges()).isTrue();
     StagedChange sc = stageChange();
     revert(sc, other, CC_ON_OWN_COMMENTS);
+
+    // email for the newly created revert change
     assertThat(sender)
         .sent("newchange", sc)
         .to(sc.owner, sc.reviewer, sc.watchingProjectOwner, admin)
         .cc(sc.ccer, other)
         .bcc(NEW_CHANGES, NEW_PATCHSETS)
-        .noOneElse(); // TODO(logan): Why not starrer/reviewers-by-email?
+        .noOneElse();
 
+    // email for the change that is reverted
     assertThat(sender)
         .sent("revert", sc)
-        .to(other)
-        .cc(sc.owner, sc.reviewer, sc.ccer, admin)
+        .to(sc.owner)
+        .cc(other, sc.reviewer, sc.ccer, admin)
+        .cc(sc.reviewerByEmail, sc.ccerByEmail)
+        .bcc(sc.starrer)
         .bcc(ALL_COMMENTS)
-        .noOneElse(); // TODO(logan): Why not starrer/reviewers-by-email?
+        .noOneElse();
   }
 
   private StagedChange stageChange() throws Exception {
diff --git a/javatests/com/google/gerrit/acceptance/server/notedb/BUILD b/javatests/com/google/gerrit/acceptance/server/notedb/BUILD
index 20c256f..4965402 100644
--- a/javatests/com/google/gerrit/acceptance/server/notedb/BUILD
+++ b/javatests/com/google/gerrit/acceptance/server/notedb/BUILD
@@ -7,5 +7,8 @@
         "notedb",
         "server",
     ],
+    # TODO(dborowitz): Fix leaks in local disk tests so we can reduce heap size.
+    # http://crbug.com/gerrit/8567
+    vm_args = ["-Xmx1024m"],
     deps = ["//java/com/google/gerrit/server/schema"],
 )
diff --git a/javatests/com/google/gerrit/acceptance/server/notedb/ChangeRebuilderIT.java b/javatests/com/google/gerrit/acceptance/server/notedb/ChangeRebuilderIT.java
index c0dcc9c..d18ef34 100644
--- a/javatests/com/google/gerrit/acceptance/server/notedb/ChangeRebuilderIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/notedb/ChangeRebuilderIT.java
@@ -15,6 +15,7 @@
 package com.google.gerrit.acceptance.server.notedb;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assert_;
 import static com.google.common.truth.TruthJUnit.assume;
 import static com.google.gerrit.reviewdb.client.RefNames.changeMetaRef;
 import static com.google.gerrit.reviewdb.client.RefNames.refsDraftComments;
@@ -23,6 +24,7 @@
 import static java.util.concurrent.TimeUnit.DAYS;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.SECONDS;
+import static java.util.stream.Collectors.joining;
 import static java.util.stream.Collectors.toList;
 import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
 
@@ -53,6 +55,7 @@
 import com.google.gerrit.reviewdb.client.PatchSetApproval;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.client.RefNames;
+import com.google.gerrit.reviewdb.client.RevId;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.reviewdb.server.ReviewDbUtil;
 import com.google.gerrit.server.ChangeUtil;
@@ -69,6 +72,8 @@
 import com.google.gerrit.server.notedb.NoteDbUpdateManager;
 import com.google.gerrit.server.notedb.TestChangeRebuilderWrapper;
 import com.google.gerrit.server.notedb.rebuild.ChangeRebuilder.NoPatchSetsException;
+import com.google.gerrit.server.patch.PatchListCache;
+import com.google.gerrit.server.patch.PatchListNotAvailableException;
 import com.google.gerrit.server.patch.PatchSetInfoFactory;
 import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
 import com.google.gerrit.server.project.testing.Util;
@@ -95,6 +100,7 @@
 import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Stream;
 import org.apache.http.Header;
 import org.apache.http.message.BasicHeader;
 import org.eclipse.jgit.junit.TestRepository;
@@ -145,6 +151,8 @@
 
   @Inject private PatchSetInfoFactory patchSetInfoFactory;
 
+  @Inject private PatchListCache patchListCache;
+
   @Before
   public void setUp() throws Exception {
     assume().that(NoteDbMode.get()).isEqualTo(NoteDbMode.OFF);
@@ -1017,8 +1025,43 @@
       db.rollback();
     }
 
-    exception.expect(NoPatchSetsException.class);
-    checker.rebuildAndCheckChanges(id);
+    try {
+      checker.rebuildAndCheckChanges(id);
+      assert_().fail("expected NoPatchSetsException");
+    } catch (NoPatchSetsException e) {
+      // Expected.
+    }
+
+    Change c = db.changes().get(id);
+    assertThat(c.getNoteDbState()).isNull();
+    checker.assertNoChangeRef(project, id);
+  }
+
+  @Test
+  public void rebuildChangeWithNoEntitiesOtherThanChange() throws Exception {
+    PushOneCommit.Result r = createChange();
+    Change.Id id = r.getPatchSetId().getParentKey();
+    db.changes().beginTransaction(id);
+    try {
+      db.changeMessages().delete(db.changeMessages().byChange(id));
+      db.patchSets().delete(db.patchSets().byChange(id));
+      db.patchSetApprovals().delete(db.patchSetApprovals().byChange(id));
+      db.patchComments().delete(db.patchComments().byChange(id));
+      db.commit();
+    } finally {
+      db.rollback();
+    }
+
+    try {
+      checker.rebuildAndCheckChanges(id);
+      assert_().fail("expected NoPatchSetsException");
+    } catch (NoPatchSetsException e) {
+      // Expected.
+    }
+
+    Change c = db.changes().get(id);
+    assertThat(c.getNoteDbState()).isNull();
+    checker.assertNoChangeRef(project, id);
   }
 
   @Test
@@ -1339,6 +1382,67 @@
     assertChangeUpToDate(true, id);
   }
 
+  @Test
+  public void missingPatchSetCommitOkForCommentsNotOnParentSide() throws Exception {
+    PushOneCommit.Result r = createChange();
+    Change.Id id = r.getChange().getId();
+
+    putDraft(user, id, 1, "draft comment", null, Side.REVISION);
+    putComment(user, id, 1, "published comment", null, Side.REVISION);
+
+    ReviewDb db = getUnwrappedDb();
+    PatchSet ps = db.patchSets().get(new PatchSet.Id(id, 1));
+    ps.setRevision(new RevId("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"));
+    db.patchSets().update(Collections.singleton(ps));
+
+    try {
+      patchListCache.getOldId(db.changes().get(id), ps, null);
+      assert_().fail("Expected PatchListNotAvailableException");
+    } catch (PatchListNotAvailableException e) {
+      // Expected.
+    }
+
+    checker.rebuildAndCheckChanges(id);
+  }
+
+  @Test
+  public void missingPatchSetCommitOmitsCommentsOnParentSide() throws Exception {
+    PushOneCommit.Result r = createChange();
+    Change.Id id = r.getChange().getId();
+
+    CommentInfo draftInfo = putDraft(user, id, 1, "draft comment", null, Side.PARENT);
+    putComment(user, id, 1, "published comment", null, Side.PARENT);
+    CommentInfo commentInfo =
+        gApi.changes()
+            .id(id.get())
+            .comments()
+            .values()
+            .stream()
+            .flatMap(List::stream)
+            .findFirst()
+            .get();
+
+    ReviewDb db = getUnwrappedDb();
+    PatchSet ps = db.patchSets().get(new PatchSet.Id(id, 1));
+    ps.setRevision(new RevId("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"));
+    db.patchSets().update(Collections.singleton(ps));
+
+    try {
+      patchListCache.getOldId(db.changes().get(id), ps, null);
+      assert_().fail("Expected PatchListNotAvailableException");
+    } catch (PatchListNotAvailableException e) {
+      // Expected.
+    }
+
+    checker.rebuildAndCheckChange(
+        id,
+        Stream.of(draftInfo.id, commentInfo.id)
+            .sorted()
+            .map(c -> id + ",1," + PushOneCommit.FILE_NAME + "," + c)
+            .collect(
+                joining(", ", "PatchLineComment.Key sets differ: [", "] only in A; [] only in B")));
+  }
+
   private void assertChangesReadOnly(RestApiException e) throws Exception {
     Throwable cause = e.getCause();
     assertThat(cause).isInstanceOf(UpdateException.class);
@@ -1388,16 +1492,24 @@
     }
   }
 
-  private void putDraft(TestAccount account, Change.Id id, int line, String msg, Boolean unresolved)
+  private CommentInfo putDraft(
+      TestAccount account, Change.Id id, int line, String msg, Boolean unresolved)
+      throws Exception {
+    return putDraft(account, id, line, msg, unresolved, Side.REVISION);
+  }
+
+  private CommentInfo putDraft(
+      TestAccount account, Change.Id id, int line, String msg, Boolean unresolved, Side side)
       throws Exception {
     DraftInput in = new DraftInput();
+    in.side = side;
     in.line = line;
     in.message = msg;
     in.path = PushOneCommit.FILE_NAME;
     in.unresolved = unresolved;
     AcceptanceTestRequestScope.Context old = setApiUser(account);
     try {
-      gApi.changes().id(id.get()).current().createDraft(in);
+      return gApi.changes().id(id.get()).current().createDraft(in).get();
     } finally {
       atrScope.set(old);
     }
@@ -1405,7 +1517,14 @@
 
   private void putComment(TestAccount account, Change.Id id, int line, String msg, String inReplyTo)
       throws Exception {
+    putComment(account, id, line, msg, inReplyTo, Side.REVISION);
+  }
+
+  private void putComment(
+      TestAccount account, Change.Id id, int line, String msg, String inReplyTo, Side side)
+      throws Exception {
     CommentInput in = new CommentInput();
+    in.side = side;
     in.line = line;
     in.message = msg;
     in.inReplyTo = inReplyTo;
diff --git a/javatests/com/google/gerrit/acceptance/server/notedb/OnlineNoteDbMigrationIT.java b/javatests/com/google/gerrit/acceptance/server/notedb/OnlineNoteDbMigrationIT.java
index d4990af..27dc951 100644
--- a/javatests/com/google/gerrit/acceptance/server/notedb/OnlineNoteDbMigrationIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/notedb/OnlineNoteDbMigrationIT.java
@@ -18,6 +18,7 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth8.assertThat;
 import static com.google.common.truth.TruthJUnit.assume;
+import static com.google.gerrit.server.notedb.NoteDbChangeState.NOTE_DB_PRIMARY_STATE;
 import static com.google.gerrit.server.notedb.NotesMigrationState.NOTE_DB;
 import static com.google.gerrit.server.notedb.NotesMigrationState.READ_WRITE_NO_SEQUENCE;
 import static com.google.gerrit.server.notedb.NotesMigrationState.READ_WRITE_WITH_SEQUENCE_NOTE_DB_PRIMARY;
@@ -43,11 +44,15 @@
 import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.gerrit.extensions.registration.RegistrationHandle;
 import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.client.RefNames;
 import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.CommentsUtil;
 import com.google.gerrit.server.Sequences;
 import com.google.gerrit.server.config.SitePaths;
+import com.google.gerrit.server.notedb.ChangeBundle;
+import com.google.gerrit.server.notedb.ChangeBundleReader;
 import com.google.gerrit.server.notedb.NoteDbChangeState;
 import com.google.gerrit.server.notedb.NoteDbChangeState.PrimaryStorage;
 import com.google.gerrit.server.notedb.NoteDbChangeState.RefState;
@@ -76,6 +81,7 @@
 import org.eclipse.jgit.lib.ObjectLoader;
 import org.eclipse.jgit.lib.ObjectReader;
 import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefUpdate;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.storage.file.FileBasedConfig;
 import org.eclipse.jgit.util.FS;
@@ -101,10 +107,12 @@
   // migration state may result in various kinds of wrappers showing up unexpectedly.
   @Inject @ReviewDbFactory private SchemaFactory<ReviewDb> schemaFactory;
 
-  @Inject private SitePaths sitePaths;
+  @Inject private ChangeBundleReader changeBundleReader;
+  @Inject private CommentsUtil commentsUtil;
+  @Inject private DynamicSet<NotesMigrationStateListener> listeners;
   @Inject private Provider<NoteDbMigrator.Builder> migratorBuilderProvider;
   @Inject private Sequences sequences;
-  @Inject private DynamicSet<NotesMigrationStateListener> listeners;
+  @Inject private SitePaths sitePaths;
 
   private FileBasedConfig noteDbConfig;
   private List<RegistrationHandle> addedListeners;
@@ -433,6 +441,67 @@
   }
 
   @Test
+  public void fullMigrationOneChangeWithNoPatchSets() throws Exception {
+    PushOneCommit.Result r1 = createChange();
+    PushOneCommit.Result r2 = createChange();
+    Change.Id id1 = r1.getChange().getId();
+    Change.Id id2 = r2.getChange().getId();
+
+    db.changes().beginTransaction(id2);
+    try {
+      db.patchSets().delete(db.patchSets().byChange(id2));
+      db.commit();
+    } finally {
+      db.rollback();
+    }
+
+    migrate(b -> b);
+    assertNotesMigrationState(NOTE_DB, false, false);
+
+    try (ReviewDb db = schemaFactory.open();
+        Repository repo = repoManager.openRepository(project)) {
+      assertThat(repo.exactRef(RefNames.changeMetaRef(id1))).isNotNull();
+      assertThat(db.changes().get(id1).getNoteDbState()).isEqualTo(NOTE_DB_PRIMARY_STATE);
+
+      // A change with no patch sets is so corrupt that it is completely skipped by the migration
+      // process.
+      assertThat(repo.exactRef(RefNames.changeMetaRef(id2))).isNull();
+      assertThat(db.changes().get(id2).getNoteDbState()).isNull();
+    }
+  }
+
+  @Test
+  public void fullMigrationMissingPatchSetRefs() throws Exception {
+    PushOneCommit.Result r = createChange();
+    Change.Id id = r.getChange().getId();
+
+    try (Repository repo = repoManager.openRepository(project)) {
+      RefUpdate u = repo.updateRef(new PatchSet.Id(id, 1).toRefName());
+      u.setForceUpdate(true);
+      assertThat(u.delete()).isEqualTo(RefUpdate.Result.FORCED);
+    }
+
+    ChangeBundle reviewDbBundle;
+    try (ReviewDb db = schemaFactory.open()) {
+      reviewDbBundle = changeBundleReader.fromReviewDb(db, id);
+    }
+
+    migrate(b -> b);
+    assertNotesMigrationState(NOTE_DB, false, false);
+
+    try (ReviewDb db = schemaFactory.open();
+        Repository repo = repoManager.openRepository(project)) {
+      // Change migrated successfully even though it was missing patch set refs.
+      assertThat(repo.exactRef(RefNames.changeMetaRef(id))).isNotNull();
+      assertThat(db.changes().get(id).getNoteDbState()).isEqualTo(NOTE_DB_PRIMARY_STATE);
+
+      ChangeBundle noteDbBundle =
+          ChangeBundle.fromNotes(commentsUtil, notesFactory.createChecked(db, project, id));
+      assertThat(noteDbBundle.differencesFrom(reviewDbBundle)).isEmpty();
+    }
+  }
+
+  @Test
   public void autoMigrationConfig() throws Exception {
     createChange();
 
diff --git a/javatests/com/google/gerrit/acceptance/ssh/QueryIT.java b/javatests/com/google/gerrit/acceptance/ssh/QueryIT.java
index 1d5af97..f741f36 100644
--- a/javatests/com/google/gerrit/acceptance/ssh/QueryIT.java
+++ b/javatests/com/google/gerrit/acceptance/ssh/QueryIT.java
@@ -46,22 +46,22 @@
     String changeId2 = createChange().getChangeId();
 
     List<ChangeAttribute> changes = executeSuccessfulQuery("1234");
-    assertThat(changes.size()).isEqualTo(0);
+    assertThat(changes).isEmpty();
 
     changes = executeSuccessfulQuery(changeId1);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).project).isEqualTo(project.toString());
     assertThat(changes.get(0).id).isEqualTo(changeId1);
 
     changes = executeSuccessfulQuery(changeId1 + " OR " + changeId2);
-    assertThat(changes.size()).isEqualTo(2);
+    assertThat(changes).hasSize(2);
     assertThat(changes.get(0).project).isEqualTo(project.toString());
     assertThat(changes.get(0).id).isEqualTo(changeId2);
     assertThat(changes.get(1).project).isEqualTo(project.toString());
     assertThat(changes.get(1).id).isEqualTo(changeId1);
 
     changes = executeSuccessfulQuery("--start=1 " + changeId1 + " OR " + changeId2);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).project).isEqualTo(project.toString());
     assertThat(changes.get(0).id).isEqualTo(changeId1);
   }
@@ -71,14 +71,14 @@
     String changeId = createChange().getChangeId();
     gApi.changes().id(changeId).current().review(ReviewInput.approve());
     List<ChangeAttribute> changes = executeSuccessfulQuery(changeId);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).patchSets).isNull();
 
     changes = executeSuccessfulQuery("--all-approvals " + changeId);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).patchSets).isNotNull();
     assertThat(changes.get(0).patchSets.get(0).approvals).isNotNull();
-    assertThat(changes.get(0).patchSets.get(0).approvals.size()).isEqualTo(1);
+    assertThat(changes.get(0).patchSets.get(0).approvals).hasSize(1);
   }
 
   @Test
@@ -89,20 +89,20 @@
     gApi.changes().id(changeId).addReviewer(in);
 
     List<ChangeAttribute> changes = executeSuccessfulQuery(changeId);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).allReviewers).isNull();
 
     changes = executeSuccessfulQuery("--all-reviewers " + changeId);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).allReviewers).isNotNull();
-    assertThat(changes.get(0).allReviewers.size()).isEqualTo(1);
+    assertThat(changes.get(0).allReviewers).hasSize(1);
   }
 
   @Test
   public void commitMessageOptionJSON() throws Exception {
     String changeId = createChange().getChangeId();
     List<ChangeAttribute> changes = executeSuccessfulQuery("--commit-message " + changeId);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).commitMessage).isNotNull();
     assertThat(changes.get(0).commitMessage).contains(PushOneCommit.SUBJECT);
   }
@@ -113,20 +113,20 @@
     amendChange(changeId);
 
     List<ChangeAttribute> changes = executeSuccessfulQuery(changeId);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).currentPatchSet).isNull();
 
     changes = executeSuccessfulQuery("--current-patch-set " + changeId);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).currentPatchSet).isNotNull();
     assertThat(changes.get(0).currentPatchSet.number).isEqualTo(2);
 
     gApi.changes().id(changeId).current().review(ReviewInput.approve());
     changes = executeSuccessfulQuery("--current-patch-set " + changeId);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).currentPatchSet).isNotNull();
     assertThat(changes.get(0).currentPatchSet.approvals).isNotNull();
-    assertThat(changes.get(0).currentPatchSet.approvals.size()).isEqualTo(1);
+    assertThat(changes.get(0).currentPatchSet.approvals).hasSize(1);
   }
 
   @Test
@@ -136,13 +136,13 @@
     amendChange(changeId);
 
     List<ChangeAttribute> changes = executeSuccessfulQuery(changeId);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).patchSets).isNull();
 
     changes = executeSuccessfulQuery("--patch-sets " + changeId);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).patchSets).isNotNull();
-    assertThat(changes.get(0).patchSets.size()).isEqualTo(3);
+    assertThat(changes.get(0).patchSets).hasSize(3);
   }
 
   @Test
@@ -159,22 +159,22 @@
 
     List<ChangeAttribute> changes =
         executeSuccessfulQuery("--current-patch-set --files " + changeId);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).currentPatchSet.files).isNotNull();
-    assertThat(changes.get(0).currentPatchSet.files.size()).isEqualTo(2);
+    assertThat(changes.get(0).currentPatchSet.files).hasSize(2);
 
     changes = executeSuccessfulQuery("--patch-sets --files " + changeId);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).patchSets.get(0).files).isNotNull();
-    assertThat(changes.get(0).patchSets.get(0).files.size()).isEqualTo(2);
+    assertThat(changes.get(0).patchSets.get(0).files).hasSize(2);
 
     gApi.changes().id(changeId).current().review(ReviewInput.approve());
     changes = executeSuccessfulQuery("--patch-sets --files --all-approvals " + changeId);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).patchSets.get(0).files).isNotNull();
-    assertThat(changes.get(0).patchSets.get(0).files.size()).isEqualTo(2);
+    assertThat(changes.get(0).patchSets.get(0).files).hasSize(2);
     assertThat(changes.get(0).patchSets.get(0).approvals).isNotNull();
-    assertThat(changes.get(0).patchSets.get(0).approvals.size()).isEqualTo(1);
+    assertThat(changes.get(0).patchSets.get(0).approvals).hasSize(1);
   }
 
   @Test
@@ -182,13 +182,13 @@
     String changeId = createChange().getChangeId();
 
     List<ChangeAttribute> changes = executeSuccessfulQuery(changeId);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).comments).isNull();
 
     changes = executeSuccessfulQuery("--comments " + changeId);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).comments).isNotNull();
-    assertThat(changes.get(0).comments.size()).isEqualTo(1);
+    assertThat(changes.get(0).comments).hasSize(1);
   }
 
   @Test
@@ -205,13 +205,13 @@
     gApi.changes().id(changeId).current().review(review);
 
     List<ChangeAttribute> changes = executeSuccessfulQuery("--current-patch-set " + changeId);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).currentPatchSet.comments).isNull();
 
     changes = executeSuccessfulQuery("--current-patch-set --comments " + changeId);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).currentPatchSet.comments).isNotNull();
-    assertThat(changes.get(0).currentPatchSet.comments.size()).isEqualTo(1);
+    assertThat(changes.get(0).currentPatchSet.comments).hasSize(1);
   }
 
   @Test
@@ -228,30 +228,30 @@
     gApi.changes().id(changeId).current().review(review);
 
     List<ChangeAttribute> changes = executeSuccessfulQuery("--patch-sets " + changeId);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).patchSets.get(0).comments).isNull();
 
     changes = executeSuccessfulQuery("--patch-sets --comments " + changeId);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).patchSets.get(0).comments).isNotNull();
-    assertThat(changes.get(0).patchSets.get(0).comments.size()).isEqualTo(1);
+    assertThat(changes.get(0).patchSets.get(0).comments).hasSize(1);
 
     changes = executeSuccessfulQuery("--patch-sets --comments --files " + changeId);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).patchSets.get(0).comments).isNotNull();
-    assertThat(changes.get(0).patchSets.get(0).comments.size()).isEqualTo(1);
+    assertThat(changes.get(0).patchSets.get(0).comments).hasSize(1);
     assertThat(changes.get(0).patchSets.get(0).files).isNotNull();
-    assertThat(changes.get(0).patchSets.get(0).files.size()).isEqualTo(2);
+    assertThat(changes.get(0).patchSets.get(0).files).hasSize(2);
 
     gApi.changes().id(changeId).current().review(ReviewInput.approve());
     changes = executeSuccessfulQuery("--patch-sets --comments --files --all-approvals " + changeId);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).patchSets.get(0).comments).isNotNull();
-    assertThat(changes.get(0).patchSets.get(0).comments.size()).isEqualTo(1);
+    assertThat(changes.get(0).patchSets.get(0).comments).hasSize(1);
     assertThat(changes.get(0).patchSets.get(0).files).isNotNull();
-    assertThat(changes.get(0).patchSets.get(0).files.size()).isEqualTo(2);
+    assertThat(changes.get(0).patchSets.get(0).files).hasSize(2);
     assertThat(changes.get(0).patchSets.get(0).approvals).isNotNull();
-    assertThat(changes.get(0).patchSets.get(0).approvals.size()).isEqualTo(1);
+    assertThat(changes.get(0).patchSets.get(0).approvals).hasSize(1);
   }
 
   @Test
@@ -259,34 +259,34 @@
     String changeId1 = createChange().getChangeId();
     String changeId2 = createChange().getChangeId();
     List<ChangeAttribute> changes = executeSuccessfulQuery(changeId1);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).dependsOn).isNull();
 
     changes = executeSuccessfulQuery("--dependencies " + changeId1);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).dependsOn).isNull();
 
     changes = executeSuccessfulQuery(changeId2);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).dependsOn).isNull();
 
     changes = executeSuccessfulQuery("--dependencies " + changeId2);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).dependsOn).isNotNull();
-    assertThat(changes.get(0).dependsOn.size()).isEqualTo(1);
+    assertThat(changes.get(0).dependsOn).hasSize(1);
   }
 
   @Test
   public void submitRecordsOptionJSON() throws Exception {
     String changeId = createChange().getChangeId();
     List<ChangeAttribute> changes = executeSuccessfulQuery(changeId);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).submitRecords).isNull();
 
     changes = executeSuccessfulQuery("--submit-records " + changeId);
-    assertThat(changes.size()).isEqualTo(1);
+    assertThat(changes).hasSize(1);
     assertThat(changes.get(0).submitRecords).isNotNull();
-    assertThat(changes.get(0).submitRecords.size()).isEqualTo(1);
+    assertThat(changes.get(0).submitRecords).hasSize(1);
   }
 
   @Test
diff --git a/javatests/com/google/gerrit/elasticsearch/BUILD b/javatests/com/google/gerrit/elasticsearch/BUILD
index 82cecfa..567595b 100644
--- a/javatests/com/google/gerrit/elasticsearch/BUILD
+++ b/javatests/com/google/gerrit/elasticsearch/BUILD
@@ -8,6 +8,7 @@
         "//java/com/google/gerrit/elasticsearch",
         "//java/com/google/gerrit/extensions:api",
         "//java/com/google/gerrit/index",
+        "//java/com/google/gerrit/index/project",
         "//java/com/google/gerrit/reviewdb:server",
         "//java/com/google/gerrit/server",
         "//lib:gson",
diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticTestUtils.java b/javatests/com/google/gerrit/elasticsearch/ElasticTestUtils.java
index d1d6611..8504890 100644
--- a/javatests/com/google/gerrit/elasticsearch/ElasticTestUtils.java
+++ b/javatests/com/google/gerrit/elasticsearch/ElasticTestUtils.java
@@ -29,14 +29,14 @@
 import com.google.gerrit.elasticsearch.ElasticGroupIndex.GroupMapping;
 import com.google.gerrit.elasticsearch.ElasticProjectIndex.ProjectMapping;
 import com.google.gerrit.index.Schema;
+import com.google.gerrit.index.project.ProjectData;
+import com.google.gerrit.index.project.ProjectSchemaDefinitions;
 import com.google.gerrit.server.account.AccountState;
 import com.google.gerrit.server.group.InternalGroup;
 import com.google.gerrit.server.index.IndexModule.IndexType;
 import com.google.gerrit.server.index.account.AccountSchemaDefinitions;
 import com.google.gerrit.server.index.change.ChangeSchemaDefinitions;
 import com.google.gerrit.server.index.group.GroupSchemaDefinitions;
-import com.google.gerrit.server.index.project.ProjectSchemaDefinitions;
-import com.google.gerrit.server.project.ProjectData;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gson.FieldNamingPolicy;
 import com.google.gson.Gson;
diff --git a/javatests/com/google/gerrit/server/git/MultiBaseLocalDiskRepositoryManagerTest.java b/javatests/com/google/gerrit/server/git/MultiBaseLocalDiskRepositoryManagerTest.java
index ddbae2c..e848fa3 100644
--- a/javatests/com/google/gerrit/server/git/MultiBaseLocalDiskRepositoryManagerTest.java
+++ b/javatests/com/google/gerrit/server/git/MultiBaseLocalDiskRepositoryManagerTest.java
@@ -84,7 +84,7 @@
         .isEqualTo(repoManager.getBasePath(someProjectKey).toAbsolutePath().toString());
 
     SortedSet<Project.NameKey> repoList = repoManager.list();
-    assertThat(repoList.size()).isEqualTo(1);
+    assertThat(repoList).hasSize(1);
     assertThat(repoList.toArray(new Project.NameKey[repoList.size()]))
         .isEqualTo(new Project.NameKey[] {someProjectKey});
   }
@@ -112,7 +112,7 @@
         .isEqualTo(alternateBasePath.toString());
 
     SortedSet<Project.NameKey> repoList = repoManager.list();
-    assertThat(repoList.size()).isEqualTo(1);
+    assertThat(repoList).hasSize(1);
     assertThat(repoList.toArray(new Project.NameKey[repoList.size()]))
         .isEqualTo(new Project.NameKey[] {someProjectKey});
   }
@@ -140,7 +140,7 @@
     createRepository(alternateBasePath, misplacedProject1);
 
     SortedSet<Project.NameKey> repoList = repoManager.list();
-    assertThat(repoList.size()).isEqualTo(2);
+    assertThat(repoList).hasSize(2);
     assertThat(repoList.toArray(new Project.NameKey[repoList.size()]))
         .isEqualTo(new Project.NameKey[] {altPathProject, basePathProject});
   }
diff --git a/javatests/com/google/gerrit/server/git/ProjectConfigTest.java b/javatests/com/google/gerrit/server/git/ProjectConfigTest.java
index 4ab7671..c46e638 100644
--- a/javatests/com/google/gerrit/server/git/ProjectConfigTest.java
+++ b/javatests/com/google/gerrit/server/git/ProjectConfigTest.java
@@ -377,7 +377,7 @@
 
     ProjectConfig cfg = read(rev);
     PluginConfig pluginCfg = cfg.getPluginConfig("somePlugin");
-    assertThat(pluginCfg.getNames().size()).isEqualTo(2);
+    assertThat(pluginCfg.getNames()).hasSize(2);
     assertThat(pluginCfg.getString("key1")).isEqualTo("value1");
     assertThat(pluginCfg.getStringList(("key2"))).isEqualTo(new String[] {"value2a", "value2b"});
   }
@@ -427,7 +427,7 @@
 
     ProjectConfig cfg = read(rev);
     PluginConfig pluginCfg = cfg.getPluginConfig("somePlugin");
-    assertThat(pluginCfg.getNames().size()).isEqualTo(1);
+    assertThat(pluginCfg.getNames()).hasSize(1);
     assertThat(pluginCfg.getGroupReference("key1")).isEqualTo(developers);
   }
 
@@ -458,7 +458,7 @@
 
     ProjectConfig cfg = read(rev);
     PluginConfig pluginCfg = cfg.getPluginConfig("somePlugin");
-    assertThat(pluginCfg.getNames().size()).isEqualTo(1);
+    assertThat(pluginCfg.getNames()).hasSize(1);
     assertThat(pluginCfg.getGroupReference("key1")).isEqualTo(developers);
 
     pluginCfg.setGroupReference("key1", staff);
diff --git a/javatests/com/google/gerrit/server/group/db/AbstractGroupTest.java b/javatests/com/google/gerrit/server/group/db/AbstractGroupTest.java
index 692a74e..ac9775a 100644
--- a/javatests/com/google/gerrit/server/group/db/AbstractGroupTest.java
+++ b/javatests/com/google/gerrit/server/group/db/AbstractGroupTest.java
@@ -137,7 +137,7 @@
 
           @Override
           public String getName() {
-            return "Group";
+            return "Group " + uuid;
           }
 
           @Nullable
diff --git a/javatests/com/google/gerrit/server/group/db/GroupNameNotesTest.java b/javatests/com/google/gerrit/server/group/db/GroupNameNotesTest.java
index c059da9..0b04764 100644
--- a/javatests/com/google/gerrit/server/group/db/GroupNameNotesTest.java
+++ b/javatests/com/google/gerrit/server/group/db/GroupNameNotesTest.java
@@ -34,8 +34,8 @@
 import com.google.gerrit.server.config.AllUsersNameProvider;
 import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
 import com.google.gerrit.server.git.MetaDataUpdate;
-import com.google.gerrit.server.group.db.testing.GroupTestUtil;
 import com.google.gerrit.server.update.RefUpdateUtil;
+import com.google.gerrit.testing.GitTestUtil;
 import com.google.gerrit.testing.TestTimeUtil;
 import com.google.gerrit.truth.ListSubject;
 import com.google.gerrit.truth.OptionalSubject;
@@ -572,7 +572,7 @@
   }
 
   private ImmutableList<CommitInfo> log() throws Exception {
-    return GroupTestUtil.log(repo, REFS_GROUPNAMES);
+    return GitTestUtil.log(repo, REFS_GROUPNAMES);
   }
 
   private String readNameNote(GroupReference g) throws Exception {
diff --git a/javatests/com/google/gerrit/server/mail/send/NotificationEmailTest.java b/javatests/com/google/gerrit/server/mail/send/NotificationEmailTest.java
new file mode 100644
index 0000000..e345535
--- /dev/null
+++ b/javatests/com/google/gerrit/server/mail/send/NotificationEmailTest.java
@@ -0,0 +1,34 @@
+// 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.server.mail.send;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+
+public class NotificationEmailTest {
+
+  @Test
+  public void getInstanceAndProjectName_returnsTheRightValue() {
+    String instanceAndProjectName = NotificationEmail.getInstanceAndProjectName("test", "/my/api");
+    assertThat(instanceAndProjectName).isEqualTo("test/api");
+  }
+
+  @Test
+  public void getInstanceAndProjectName_handlesNull() {
+    String instanceAndProjectName = NotificationEmail.getInstanceAndProjectName(null, "/my/api");
+    assertThat(instanceAndProjectName).isEqualTo("...api");
+  }
+}
diff --git a/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java b/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
index 4f14dda..e930f11 100644
--- a/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
+++ b/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
@@ -19,14 +19,24 @@
 import static java.util.stream.Collectors.toList;
 import static org.junit.Assert.fail;
 
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Streams;
 import com.google.gerrit.extensions.api.GerritApi;
+import com.google.gerrit.extensions.api.access.AccessSectionInfo;
+import com.google.gerrit.extensions.api.access.PermissionInfo;
+import com.google.gerrit.extensions.api.access.PermissionRuleInfo;
+import com.google.gerrit.extensions.api.access.ProjectAccessInput;
 import com.google.gerrit.extensions.api.accounts.Accounts.QueryRequest;
+import com.google.gerrit.extensions.api.groups.GroupInput;
+import com.google.gerrit.extensions.api.projects.ProjectInput;
 import com.google.gerrit.extensions.client.ListAccountsOption;
 import com.google.gerrit.extensions.client.ProjectWatchInfo;
 import com.google.gerrit.extensions.common.AccountExternalIdInfo;
 import com.google.gerrit.extensions.common.AccountInfo;
+import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.common.ChangeInput;
+import com.google.gerrit.extensions.common.GroupInfo;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.BadRequestException;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
@@ -62,6 +72,7 @@
 import com.google.gerrit.server.git.MetaDataUpdate;
 import com.google.gerrit.server.index.account.AccountField;
 import com.google.gerrit.server.index.account.AccountIndexCollection;
+import com.google.gerrit.server.index.account.AccountIndexer;
 import com.google.gerrit.server.schema.SchemaCreator;
 import com.google.gerrit.server.util.ManualRequestContext;
 import com.google.gerrit.server.util.OneOffRequestContext;
@@ -75,6 +86,7 @@
 import com.google.inject.util.Providers;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Optional;
@@ -93,6 +105,8 @@
 
   @Inject protected AccountCache accountCache;
 
+  @Inject protected AccountIndexer accountIndexer;
+
   @Inject protected AccountManager accountManager;
 
   @Inject protected GerritApi gApi;
@@ -393,6 +407,22 @@
   }
 
   @Test
+  public void byCansee() throws Exception {
+    String domain = name("test.com");
+    AccountInfo user1 = newAccountWithEmail("account1", "account1@" + domain);
+    AccountInfo user2 = newAccountWithEmail("account2", "account2@" + domain);
+    AccountInfo user3 = newAccountWithEmail("account3", "account3@" + domain);
+
+    Project.NameKey p = createProject(name("p"));
+    ChangeInfo c = createChange(p);
+    assertQuery("name:" + domain + " cansee:" + c.changeId, user1, user2, user3);
+
+    GroupInfo group = createGroup(name("group"), user1, user2);
+    blockRead(p, group);
+    assertQuery("name:" + domain + " cansee:" + c.changeId, user3);
+  }
+
+  @Test
   public void byWatchedProject() throws Exception {
     Project.NameKey p = createProject(name("p"));
     Project.NameKey p2 = createProject(name("p2"));
@@ -614,10 +644,43 @@
   }
 
   protected Project.NameKey createProject(String name) throws RestApiException {
-    gApi.projects().create(name);
+    ProjectInput in = new ProjectInput();
+    in.name = name;
+    in.createEmptyCommit = true;
+    gApi.projects().create(in);
     return new Project.NameKey(name);
   }
 
+  protected void blockRead(Project.NameKey project, GroupInfo group) throws RestApiException {
+    ProjectAccessInput in = new ProjectAccessInput();
+    in.add = new HashMap<>();
+
+    AccessSectionInfo a = new AccessSectionInfo();
+    PermissionInfo p = new PermissionInfo(null, null);
+    p.rules =
+        ImmutableMap.of(group.id, new PermissionRuleInfo(PermissionRuleInfo.Action.BLOCK, false));
+    a.permissions = ImmutableMap.of("read", p);
+    in.add = ImmutableMap.of("refs/*", a);
+
+    gApi.projects().name(project.get()).access(in);
+  }
+
+  protected ChangeInfo createChange(Project.NameKey project) throws RestApiException {
+    ChangeInput in = new ChangeInput();
+    in.subject = "A change";
+    in.project = project.get();
+    in.branch = "master";
+    return gApi.changes().create(in).get();
+  }
+
+  protected GroupInfo createGroup(String name, AccountInfo... members) throws RestApiException {
+    GroupInput in = new GroupInput();
+    in.name = name;
+    in.members =
+        Arrays.asList(members).stream().map(a -> String.valueOf(a._accountId)).collect(toList());
+    return gApi.groups().create(in).get();
+  }
+
   protected void watch(AccountInfo account, Project.NameKey project, String filter)
       throws RestApiException {
     List<ProjectWatchInfo> projectsToWatch = new ArrayList<>();
@@ -672,6 +735,7 @@
       accountManager.link(id, AuthRequest.forEmail(email));
     }
     accountCache.evict(id);
+    accountIndexer.index(id);
   }
 
   protected QueryRequest newQuery(Object query) throws RestApiException {
diff --git a/javatests/com/google/gerrit/server/query/account/BUILD b/javatests/com/google/gerrit/server/query/account/BUILD
index e0b59d5..497fc22 100644
--- a/javatests/com/google/gerrit/server/query/account/BUILD
+++ b/javatests/com/google/gerrit/server/query/account/BUILD
@@ -19,6 +19,7 @@
         "//lib:truth-java8-extension",
         "//lib/guice",
         "//lib/jgit/org.eclipse.jgit:jgit",
+        "//prolog:gerrit-prolog-common",
     ],
 )
 
diff --git a/javatests/com/google/gerrit/server/query/project/BUILD b/javatests/com/google/gerrit/server/query/project/BUILD
index 760aa36..4ad9e73 100644
--- a/javatests/com/google/gerrit/server/query/project/BUILD
+++ b/javatests/com/google/gerrit/server/query/project/BUILD
@@ -30,6 +30,7 @@
     visibility = ["//visibility:public"],
     deps = [
         ":abstract_query_tests",
+        "//java/com/google/gerrit/index/project",
         "//java/com/google/gerrit/server",
         "//java/com/google/gerrit/testing:gerrit-test-util",
         "//javatests/com/google/gerrit/server/query:index-config",
diff --git a/javatests/com/google/gerrit/server/query/project/LuceneQueryProjectsTest.java b/javatests/com/google/gerrit/server/query/project/LuceneQueryProjectsTest.java
index a537dc9..1cf09d8 100644
--- a/javatests/com/google/gerrit/server/query/project/LuceneQueryProjectsTest.java
+++ b/javatests/com/google/gerrit/server/query/project/LuceneQueryProjectsTest.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.query.project;
 
-import com.google.gerrit.server.index.project.ProjectSchemaDefinitions;
+import com.google.gerrit.index.project.ProjectSchemaDefinitions;
 import com.google.gerrit.server.query.IndexConfig;
 import com.google.gerrit.testing.ConfigSuite;
 import com.google.gerrit.testing.InMemoryModule;
@@ -36,7 +36,7 @@
     // the current schema version is already tested by the inherited default config suite
     List<Integer> schemaVersions =
         IndexVersions.getWithoutLatest(
-            com.google.gerrit.server.index.project.ProjectSchemaDefinitions.INSTANCE);
+            com.google.gerrit.index.project.ProjectSchemaDefinitions.INSTANCE);
     return IndexVersions.asConfigMap(
         ProjectSchemaDefinitions.INSTANCE, schemaVersions, "againstIndexVersion", defaultConfig());
   }
diff --git a/javatests/com/google/gerrit/server/group/db/GroupBundleTest.java b/javatests/com/google/gerrit/server/schema/GroupBundleTest.java
similarity index 98%
rename from javatests/com/google/gerrit/server/group/db/GroupBundleTest.java
rename to javatests/com/google/gerrit/server/schema/GroupBundleTest.java
index b449090..43fd59a 100644
--- a/javatests/com/google/gerrit/server/group/db/GroupBundleTest.java
+++ b/javatests/com/google/gerrit/server/schema/GroupBundleTest.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.group.db;
+package com.google.gerrit.server.schema;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -23,7 +23,7 @@
 import com.google.gerrit.reviewdb.client.AccountGroupByIdAud;
 import com.google.gerrit.reviewdb.client.AccountGroupMember;
 import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
-import com.google.gerrit.server.group.db.GroupBundle.Source;
+import com.google.gerrit.server.schema.GroupBundle.Source;
 import com.google.gerrit.testing.GerritBaseTests;
 import com.google.gerrit.testing.TestTimeUtil;
 import java.sql.Timestamp;
diff --git a/javatests/com/google/gerrit/server/schema/GroupRebuilderIT.java b/javatests/com/google/gerrit/server/schema/GroupRebuilderIT.java
new file mode 100644
index 0000000..709be8e
--- /dev/null
+++ b/javatests/com/google/gerrit/server/schema/GroupRebuilderIT.java
@@ -0,0 +1,300 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.schema;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.TruthJUnit.assume;
+import static com.google.gerrit.extensions.common.testing.CommitInfoSubject.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.gerrit.common.TimeUtil;
+import com.google.gerrit.extensions.api.GerritApi;
+import com.google.gerrit.extensions.api.accounts.AccountInput;
+import com.google.gerrit.extensions.common.AccountInfo;
+import com.google.gerrit.extensions.common.CommitInfo;
+import com.google.gerrit.extensions.common.GroupInfo;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupById;
+import com.google.gerrit.reviewdb.client.AccountGroupByIdAud;
+import com.google.gerrit.reviewdb.client.RefNames;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.GerritPersonIdent;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.ServerInitiated;
+import com.google.gerrit.server.account.AccountCache;
+import com.google.gerrit.server.account.AccountsUpdate;
+import com.google.gerrit.server.account.GroupBackend;
+import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.config.GerritServerId;
+import com.google.gerrit.server.config.GerritServerIdProvider;
+import com.google.gerrit.server.git.CommitUtil;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.group.SystemGroupBackend;
+import com.google.gerrit.server.group.db.AuditLogFormatter;
+import com.google.gerrit.server.notedb.GroupsMigration;
+import com.google.gerrit.testing.GerritBaseTests;
+import com.google.gerrit.testing.InMemoryTestEnvironment;
+import com.google.gerrit.testing.TestTimeUtil;
+import com.google.gerrit.testing.TestTimeUtil.TempClockStep;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevSort;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class GroupRebuilderIT extends GerritBaseTests {
+
+  private static Config createConfigWithServerId() {
+    Config config = new Config();
+    config.setString(GerritServerIdProvider.SECTION, null, GerritServerIdProvider.KEY, "1234567");
+    return config;
+  }
+
+  @Rule
+  public InMemoryTestEnvironment testEnv =
+      new InMemoryTestEnvironment(GroupRebuilderIT::createConfigWithServerId);
+
+  @Inject private GroupsMigration migration;
+  @Inject private GerritApi gApi;
+  @Inject private ReviewDb db;
+  @Inject private GitRepositoryManager repoManager;
+  @Inject private AllUsersName allUsersName;
+  @Inject private IdentifiedUser currentUser;
+  @Inject private @GerritServerId String serverId;
+  @Inject private AccountCache accountCache;
+  @Inject private @ServerInitiated AccountsUpdate accountsUpdate;
+  @Inject private GroupBackend groupBackend;
+  @Inject private GroupBundle.Factory bundleFactory;
+  @Inject private @GerritPersonIdent Provider<PersonIdent> serverIdent;
+
+  private GroupRebuilder rebuilder;
+
+  @Before
+  public void setup() throws Exception {
+    // This test is explicitly testing the migration from ReviewDb to NoteDb, and handles reading
+    // from NoteDb manually. It should work regardless of the value of noteDb.groups.write, however.
+    assume().that(migration.readFromNoteDb()).isFalse();
+
+    accountsUpdate.update(
+        "Set Name for CurrentUser", currentUser.getAccountId(), u -> u.setFullName("current"));
+
+    AuditLogFormatter auditLogFormatter =
+        AuditLogFormatter.createBackedBy(accountCache, groupBackend, serverId);
+    rebuilder = new GroupRebuilder(serverIdent.get(), allUsersName, auditLogFormatter);
+  }
+
+  @Before
+  public void setTimeForTesting() {
+    TestTimeUtil.resetWithClockStep(1, TimeUnit.SECONDS);
+  }
+
+  @After
+  public void resetTime() {
+    TestTimeUtil.useSystemTime();
+  }
+
+  @Test
+  public void basicGroupProperties() throws Exception {
+    GroupInfo createdGroup = gApi.groups().create("group").get();
+    GroupBundle reviewDbBundle =
+        GroupBundle.Factory.fromReviewDb(db, new AccountGroup.UUID(createdGroup.id));
+
+    deleteGroupRefs(reviewDbBundle);
+    assertMigratedCleanly(rebuild(reviewDbBundle), reviewDbBundle);
+  }
+
+  @Test
+  public void logFormat() throws Exception {
+    AccountInfo user1 = createAccount("user1");
+    AccountInfo user2 = createAccount("user2");
+    GroupInfo group1 = gApi.groups().create("group1").get();
+    GroupInfo group2 = gApi.groups().create("group2").get();
+
+    try (TempClockStep step = TestTimeUtil.freezeClock()) {
+      gApi.groups()
+          .id(group1.id)
+          .addMembers(Integer.toString(user1._accountId), Integer.toString(user2._accountId));
+    }
+    TimeUtil.nowTs();
+
+    try (TempClockStep step = TestTimeUtil.freezeClock()) {
+      gApi.groups().id(group1.id).addGroups(group2.id, SystemGroupBackend.REGISTERED_USERS.get());
+    }
+
+    GroupBundle reviewDbBundle =
+        GroupBundle.Factory.fromReviewDb(db, new AccountGroup.UUID(group1.id));
+    deleteGroupRefs(reviewDbBundle);
+
+    GroupBundle noteDbBundle = rebuild(reviewDbBundle);
+    assertMigratedCleanly(noteDbBundle, reviewDbBundle);
+
+    ImmutableList<CommitInfo> log = log(group1);
+    assertThat(log).hasSize(4);
+
+    assertThat(log.get(0)).message().isEqualTo("Create group");
+    assertThat(log.get(0)).author().name().isEqualTo(serverIdent.get().getName());
+    assertThat(log.get(0)).author().email().isEqualTo(serverIdent.get().getEmailAddress());
+    assertThat(log.get(0)).author().date().isEqualTo(noteDbBundle.group().getCreatedOn());
+    assertThat(log.get(0)).author().tz().isEqualTo(serverIdent.get().getTimeZoneOffset());
+    assertThat(log.get(0)).committer().isEqualTo(log.get(0).author);
+
+    assertThat(log.get(1))
+        .message()
+        .isEqualTo(
+            "Update group\n\nAdd: "
+                + currentUser.getName()
+                + " <"
+                + currentUser.getAccountId()
+                + "@"
+                + serverId
+                + ">");
+    assertThat(log.get(1)).author().name().isEqualTo(currentUser.getName());
+    assertThat(log.get(1)).author().email().isEqualTo(currentUser.getAccountId() + "@" + serverId);
+    assertThat(log.get(1)).committer().hasSameDateAs(log.get(1).author);
+
+    assertThat(log.get(2))
+        .message()
+        .isEqualTo(
+            "Update group\n"
+                + "\n"
+                + ("Add: user1 <" + user1._accountId + "@" + serverId + ">\n")
+                + ("Add: user2 <" + user2._accountId + "@" + serverId + ">"));
+    assertThat(log.get(2)).author().name().isEqualTo(currentUser.getName());
+    assertThat(log.get(2)).author().email().isEqualTo(currentUser.getAccountId() + "@" + serverId);
+    assertThat(log.get(2)).committer().hasSameDateAs(log.get(2).author);
+
+    assertThat(log.get(3))
+        .message()
+        .isEqualTo(
+            "Update group\n"
+                + "\n"
+                + ("Add-group: " + group2.name + " <" + group2.id + ">\n")
+                + ("Add-group: Registered Users <global:Registered-Users>"));
+    assertThat(log.get(3)).author().name().isEqualTo(currentUser.getName());
+    assertThat(log.get(3)).author().email().isEqualTo(currentUser.getAccountId() + "@" + serverId);
+    assertThat(log.get(3)).committer().hasSameDateAs(log.get(3).author);
+  }
+
+  @Test
+  public void unknownGroupUuid() throws Exception {
+    GroupInfo group = gApi.groups().create("group").get();
+
+    AccountGroup.UUID subgroupUuid = new AccountGroup.UUID("mybackend:foo");
+
+    AccountGroupById byId =
+        new AccountGroupById(
+            new AccountGroupById.Key(new AccountGroup.Id(group.groupId), subgroupUuid));
+    assertThat(groupBackend.handles(byId.getIncludeUUID())).isFalse();
+    db.accountGroupById().insert(Collections.singleton(byId));
+
+    AccountGroupByIdAud audit =
+        new AccountGroupByIdAud(byId, currentUser.getAccountId(), TimeUtil.nowTs());
+    db.accountGroupByIdAud().insert(Collections.singleton(audit));
+
+    GroupBundle reviewDbBundle =
+        GroupBundle.Factory.fromReviewDb(db, new AccountGroup.UUID(group.id));
+    deleteGroupRefs(reviewDbBundle);
+
+    GroupBundle noteDbBundle = rebuild(reviewDbBundle);
+    assertMigratedCleanly(noteDbBundle, reviewDbBundle);
+
+    ImmutableList<CommitInfo> log = log(group);
+    assertThat(log).hasSize(3);
+
+    assertThat(log.get(0)).message().isEqualTo("Create group");
+    assertThat(log.get(1))
+        .message()
+        .isEqualTo(
+            "Update group\n\nAdd: "
+                + currentUser.getName()
+                + " <"
+                + currentUser.getAccountId()
+                + "@"
+                + serverId
+                + ">");
+    assertThat(log.get(2))
+        .message()
+        .isEqualTo("Update group\n\nAdd-group: mybackend:foo <mybackend:foo>");
+  }
+
+  private void deleteGroupRefs(GroupBundle bundle) throws Exception {
+    try (Repository repo = repoManager.openRepository(allUsersName)) {
+      String refName = RefNames.refsGroups(bundle.uuid());
+      RefUpdate ru = repo.updateRef(refName);
+      ru.setForceUpdate(true);
+      Ref oldRef = repo.exactRef(refName);
+      if (oldRef == null) {
+        return;
+      }
+      ru.setExpectedOldObjectId(oldRef.getObjectId());
+      ru.setNewObjectId(ObjectId.zeroId());
+      assertThat(ru.delete()).isEqualTo(RefUpdate.Result.FORCED);
+    }
+  }
+
+  private GroupBundle rebuild(GroupBundle reviewDbBundle) throws Exception {
+    try (Repository repo = repoManager.openRepository(allUsersName)) {
+      rebuilder.rebuild(repo, reviewDbBundle, null);
+      return bundleFactory.fromNoteDb(repo, reviewDbBundle.uuid());
+    }
+  }
+
+  private void assertMigratedCleanly(GroupBundle noteDbBundle, GroupBundle expectedReviewDbBundle) {
+    assertThat(GroupBundle.compareWithAudits(expectedReviewDbBundle, noteDbBundle)).isEmpty();
+  }
+
+  private AccountInfo createAccount(String name) throws RestApiException {
+    AccountInput accountInput = new AccountInput();
+    accountInput.username = name;
+    accountInput.name = name;
+    return gApi.accounts().create(accountInput).get();
+  }
+
+  private ImmutableList<CommitInfo> log(GroupInfo g) throws Exception {
+    ImmutableList.Builder<CommitInfo> result = ImmutableList.builder();
+    List<Date> commitDates = new ArrayList<>();
+    try (Repository repo = repoManager.openRepository(allUsersName);
+        RevWalk rw = new RevWalk(repo)) {
+      Ref ref = repo.exactRef(RefNames.refsGroups(new AccountGroup.UUID(g.id)));
+      if (ref != null) {
+        rw.sort(RevSort.REVERSE);
+        rw.setRetainBody(true);
+        rw.markStart(rw.parseCommit(ref.getObjectId()));
+        for (RevCommit c : rw) {
+          result.add(CommitUtil.toCommitInfo(c));
+          commitDates.add(c.getCommitterIdent().getWhen());
+        }
+      }
+    }
+    assertThat(commitDates).named("commit timestamps for %s", result).isOrdered();
+    return result.build();
+  }
+}
diff --git a/javatests/com/google/gerrit/server/group/db/GroupRebuilderTest.java b/javatests/com/google/gerrit/server/schema/GroupRebuilderTest.java
similarity index 81%
rename from javatests/com/google/gerrit/server/group/db/GroupRebuilderTest.java
rename to javatests/com/google/gerrit/server/schema/GroupRebuilderTest.java
index e015994..6c670c0 100644
--- a/javatests/com/google/gerrit/server/group/db/GroupRebuilderTest.java
+++ b/javatests/com/google/gerrit/server/schema/GroupRebuilderTest.java
@@ -12,15 +12,18 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.group.db;
+package com.google.gerrit.server.schema;
 
 import static com.google.common.collect.ImmutableList.toImmutableList;
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assert_;
+import static com.google.gerrit.extensions.common.testing.CommitInfoSubject.assertThat;
 import static com.google.gerrit.reviewdb.client.RefNames.REFS_GROUPNAMES;
 
 import com.google.common.collect.ImmutableList;
+import com.google.gerrit.common.Nullable;
 import com.google.gerrit.common.TimeUtil;
+import com.google.gerrit.common.data.GroupDescription;
 import com.google.gerrit.common.data.GroupReference;
 import com.google.gerrit.extensions.common.CommitInfo;
 import com.google.gerrit.reviewdb.client.Account;
@@ -30,25 +33,38 @@
 import com.google.gerrit.reviewdb.client.AccountGroupMember;
 import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
 import com.google.gerrit.reviewdb.client.RefNames;
-import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
-import com.google.gerrit.server.git.MetaDataUpdate;
-import com.google.gerrit.server.group.db.testing.GroupTestUtil;
+import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.config.AllUsersNameProvider;
+import com.google.gerrit.server.group.db.AuditLogFormatter;
+import com.google.gerrit.server.group.db.AuditLogReader;
+import com.google.gerrit.server.group.db.GroupNameNotes;
 import com.google.gerrit.server.update.RefUpdateUtil;
+import com.google.gerrit.testing.GerritBaseTests;
+import com.google.gerrit.testing.GitTestUtil;
+import com.google.gerrit.testing.InMemoryRepositoryManager;
 import com.google.gerrit.testing.TestTimeUtil;
 import com.google.gwtorm.server.OrmDuplicateKeyException;
 import java.sql.Timestamp;
+import java.util.Optional;
+import java.util.TimeZone;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.IntStream;
 import org.eclipse.jgit.lib.BatchRefUpdate;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.PersonIdent;
 import org.eclipse.jgit.lib.Repository;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-public class GroupRebuilderTest extends AbstractGroupTest {
+public class GroupRebuilderTest extends GerritBaseTests {
+  private static final TimeZone TZ = TimeZone.getTimeZone("America/Los_Angeles");
+  private static final String SERVER_ID = "server-id";
+  private static final String SERVER_NAME = "Gerrit Server";
+  private static final String SERVER_EMAIL = "noreply@gerritcodereview.com";
+
   private AtomicInteger idCounter;
   private Repository repo;
   private GroupRebuilder rebuilder;
@@ -58,16 +74,14 @@
   public void setUp() throws Exception {
     TestTimeUtil.resetWithClockStep(1, TimeUnit.SECONDS);
     idCounter = new AtomicInteger();
-    repo = repoManager.createRepository(allUsersName);
+    AllUsersName allUsersName = new AllUsersName(AllUsersNameProvider.DEFAULT);
+    repo = new InMemoryRepositoryManager().createRepository(allUsersName);
     rebuilder =
         new GroupRebuilder(
-            GroupRebuilderTest::newPersonIdent,
+            GroupRebuilderTest.newPersonIdent(),
             allUsersName,
-            (project, repo, batch) ->
-                new MetaDataUpdate(GitReferenceUpdated.DISABLED, project, repo, batch),
             // Note that the expected name/email values in tests are not necessarily realistic,
-            // since they use these trivial name/email functions. GroupRebuilderIT checks the actual
-            // values.
+            // since they use these trivial name/email functions.
             getAuditLogFormatter());
     bundleFactory = new GroupBundle.Factory(new AuditLogReader(SERVER_ID));
   }
@@ -169,8 +183,8 @@
             + "\n"
             + "Add: Account 1 <1@server-id>\n"
             + "Add: Account 2 <2@server-id>\n"
-            + "Add-group: Group <x>\n"
-            + "Add-group: Group <y>");
+            + "Add-group: Group x <x>\n"
+            + "Add-group: Group y <y>");
   }
 
   @Test
@@ -267,9 +281,10 @@
     ImmutableList<CommitInfo> log = log(g);
     assertThat(log).hasSize(4);
     assertServerCommit(log.get(0), "Create group");
-    assertCommit(log.get(1), "Update group\n\nAdd-group: Group <y>", "Account 8", "8@server-id");
-    assertCommit(log.get(2), "Update group\n\nAdd-group: Group <x>", "Account 8", "8@server-id");
-    assertCommit(log.get(3), "Update group\n\nRemove-group: Group <y>", "Account 9", "9@server-id");
+    assertCommit(log.get(1), "Update group\n\nAdd-group: Group y <y>", "Account 8", "8@server-id");
+    assertCommit(log.get(2), "Update group\n\nAdd-group: Group x <x>", "Account 8", "8@server-id");
+    assertCommit(
+        log.get(3), "Update group\n\nRemove-group: Group y <y>", "Account 9", "9@server-id");
   }
 
   @Test
@@ -288,8 +303,9 @@
     ImmutableList<CommitInfo> log = log(g);
     assertThat(log).hasSize(3);
     assertServerCommit(log.get(0), "Create group");
-    assertCommit(log.get(1), "Update group\n\nAdd-group: Group <x>", "Account 8", "8@server-id");
-    assertServerCommit(log.get(2), "Update group\n\nAdd-group: Group <y>\nAdd-group: Group <z>");
+    assertCommit(log.get(1), "Update group\n\nAdd-group: Group x <x>", "Account 8", "8@server-id");
+    assertServerCommit(
+        log.get(2), "Update group\n\nAdd-group: Group y <y>\nAdd-group: Group z <z>");
   }
 
   @Test
@@ -333,12 +349,13 @@
         log.get(3),
         "Update group\n"
             + "\n"
-            + "Add-group: Group <x>\n"
-            + "Add-group: Group <y>\n"
-            + "Add-group: Group <z>",
+            + "Add-group: Group x <x>\n"
+            + "Add-group: Group y <y>\n"
+            + "Add-group: Group z <z>",
         "Account 8",
         "8@server-id");
-    assertCommit(log.get(4), "Update group\n\nRemove-group: Group <z>", "Account 8", "8@server-id");
+    assertCommit(
+        log.get(4), "Update group\n\nRemove-group: Group z <z>", "Account 8", "8@server-id");
   }
 
   @Test
@@ -372,12 +389,12 @@
         "8@server-id");
     assertCommit(
         log.get(2),
-        "Update group\n\nAdd-group: Group <x>\nAdd-group: Group <z>",
+        "Update group\n\nAdd-group: Group x <x>\nAdd-group: Group z <z>",
         "Account 8",
         "8@server-id");
     assertCommit(
         log.get(3), "Update group\n\nAdd: Account 2 <2@server-id>", "Account 9", "9@server-id");
-    assertCommit(log.get(4), "Update group\n\nAdd-group: Group <y>", "Account 9", "9@server-id");
+    assertCommit(log.get(4), "Update group\n\nAdd-group: Group y <y>", "Account 9", "9@server-id");
   }
 
   @Test
@@ -400,8 +417,9 @@
     ImmutableList<CommitInfo> log = log(g);
     assertThat(log).hasSize(3);
     assertServerCommit(log.get(0), "Create group");
-    assertCommit(log.get(1), "Update group\n\nAdd-group: Group <x>", "Account 8", "8@server-id");
-    assertServerCommit(log.get(2), "Update group\n\nAdd-group: Group <y>\nAdd-group: Group <z>");
+    assertCommit(log.get(1), "Update group\n\nAdd-group: Group x <x>", "Account 8", "8@server-id");
+    assertServerCommit(
+        log.get(2), "Update group\n\nAdd-group: Group y <y>\nAdd-group: Group z <z>");
 
     assertThat(log.stream().map(c -> c.committer.date).collect(toImmutableList()))
         .named("%s", log)
@@ -515,8 +533,9 @@
     ImmutableList<CommitInfo> log = log(g);
     assertThat(log).hasSize(3);
     assertServerCommit(log.get(0), "Create group");
-    assertCommit(log.get(1), "Update group\n\nAdd-group: Group <x>", "Account 8", "8@server-id");
-    assertCommit(log.get(2), "Update group\n\nRemove-group: Group <x>", "Account 9", "9@server-id");
+    assertCommit(log.get(1), "Update group\n\nAdd-group: Group x <x>", "Account 8", "8@server-id");
+    assertCommit(
+        log.get(2), "Update group\n\nRemove-group: Group x <x>", "Account 9", "9@server-id");
   }
 
   @Test
@@ -655,14 +674,74 @@
   }
 
   private ImmutableList<CommitInfo> log(AccountGroup g) throws Exception {
-    return GroupTestUtil.log(repo, RefNames.refsGroups(g.getGroupUUID()));
+    return GitTestUtil.log(repo, RefNames.refsGroups(g.getGroupUUID()));
   }
 
   private ImmutableList<CommitInfo> logGroupNames() throws Exception {
-    return GroupTestUtil.log(repo, REFS_GROUPNAMES);
+    return GitTestUtil.log(repo, REFS_GROUPNAMES);
   }
 
   private static GroupBundle.Builder builder() {
     return GroupBundle.builder().source(GroupBundle.Source.REVIEW_DB);
   }
+
+  private static PersonIdent newPersonIdent() {
+    return new PersonIdent(SERVER_NAME, SERVER_EMAIL, TimeUtil.nowTs(), TZ);
+  }
+
+  private static void assertServerCommit(CommitInfo commitInfo, String expectedMessage) {
+    assertCommit(commitInfo, expectedMessage, SERVER_NAME, SERVER_EMAIL);
+  }
+
+  private static void assertCommit(
+      CommitInfo commitInfo, String expectedMessage, String expectedName, String expectedEmail) {
+    assertThat(commitInfo).message().isEqualTo(expectedMessage);
+    assertThat(commitInfo).author().name().isEqualTo(expectedName);
+    assertThat(commitInfo).author().email().isEqualTo(expectedEmail);
+
+    // Committer should always be the server, regardless of author.
+    assertThat(commitInfo).committer().name().isEqualTo(SERVER_NAME);
+    assertThat(commitInfo).committer().email().isEqualTo(SERVER_EMAIL);
+    assertThat(commitInfo).committer().date().isEqualTo(commitInfo.author.date);
+    assertThat(commitInfo).committer().tz().isEqualTo(commitInfo.author.tz);
+  }
+
+  private static AuditLogFormatter getAuditLogFormatter() {
+    return AuditLogFormatter.create(
+        GroupRebuilderTest::getAccount, GroupRebuilderTest::getGroup, SERVER_ID);
+  }
+
+  private static Optional<Account> getAccount(Account.Id id) {
+    Account account = new Account(id, TimeUtil.nowTs());
+    account.setFullName("Account " + id);
+    return Optional.of(account);
+  }
+
+  private static Optional<GroupDescription.Basic> getGroup(AccountGroup.UUID uuid) {
+    GroupDescription.Basic group =
+        new GroupDescription.Basic() {
+          @Override
+          public AccountGroup.UUID getGroupUUID() {
+            return uuid;
+          }
+
+          @Override
+          public String getName() {
+            return "Group " + uuid;
+          }
+
+          @Nullable
+          @Override
+          public String getEmailAddress() {
+            return null;
+          }
+
+          @Nullable
+          @Override
+          public String getUrl() {
+            return null;
+          }
+        };
+    return Optional.of(group);
+  }
 }
diff --git a/javatests/com/google/gerrit/server/schema/Schema_159_to_160_Test.java b/javatests/com/google/gerrit/server/schema/Schema_159_to_160_Test.java
index a77f807..a01d611 100644
--- a/javatests/com/google/gerrit/server/schema/Schema_159_to_160_Test.java
+++ b/javatests/com/google/gerrit/server/schema/Schema_159_to_160_Test.java
@@ -14,14 +14,19 @@
 
 package com.google.gerrit.server.schema;
 
+import static com.google.common.base.MoreObjects.firstNonNull;
 import static com.google.common.collect.ImmutableMap.toImmutableMap;
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth8.assertThat;
+import static com.google.gerrit.reviewdb.client.RefNames.REFS_USERS_DEFAULT;
 import static com.google.gerrit.server.git.UserConfigSections.KEY_URL;
 import static com.google.gerrit.server.git.UserConfigSections.MY;
-import static com.google.gerrit.server.schema.Schema_160.DEFAULT_DRAFT_ITEM;
+import static com.google.gerrit.server.schema.Schema_160.DEFAULT_DRAFT_ITEMS;
+import static com.google.gerrit.server.schema.VersionedAccountPreferences.PREFERENCES;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.gerrit.extensions.api.GerritApi;
 import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
 import com.google.gerrit.extensions.client.MenuItem;
@@ -32,13 +37,19 @@
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.config.AllUsersName;
 import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.index.account.AccountIndexer;
 import com.google.gerrit.testing.InMemoryTestEnvironment;
 import com.google.gerrit.testing.TestUpdateUI;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import java.util.List;
+import java.util.Optional;
+import java.util.function.Supplier;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.BlobBasedConfig;
 import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Repository;
 import org.junit.Before;
 import org.junit.Rule;
@@ -48,6 +59,7 @@
   @Rule public InMemoryTestEnvironment testEnv = new InMemoryTestEnvironment();
 
   @Inject private AccountCache accountCache;
+  @Inject private AccountIndexer accountIndexer;
   @Inject private AllUsersName allUsersName;
   @Inject private GerritApi gApi;
   @Inject private GitRepositoryManager repoManager;
@@ -65,8 +77,12 @@
   @Test
   public void skipUnmodified() throws Exception {
     ObjectId oldMetaId = metaRef(accountId);
-    assertThat(myMenusFromNoteDb(accountId).values()).doesNotContain(DEFAULT_DRAFT_ITEM);
-    assertThat(myMenusFromApi(accountId).values()).doesNotContain(DEFAULT_DRAFT_ITEM);
+    ImmutableSet<String> fromNoteDb = myMenusFromNoteDb(accountId);
+    ImmutableSet<String> fromApi = myMenusFromApi(accountId);
+    for (String item : DEFAULT_DRAFT_ITEMS) {
+      assertThat(fromNoteDb).doesNotContain(item);
+      assertThat(fromApi).doesNotContain(item);
+    }
 
     schema160.migrateData(db, new TestUpdateUI());
 
@@ -76,39 +92,103 @@
   @Test
   public void deleteItems() throws Exception {
     ObjectId oldMetaId = metaRef(accountId);
-    List<String> defaultNames = ImmutableList.copyOf(myMenusFromApi(accountId).keySet());
+    ImmutableSet<String> defaultNames = myMenusFromApi(accountId);
 
     GeneralPreferencesInfo prefs = gApi.accounts().id(accountId.get()).getPreferences();
-    prefs.my.add(0, new MenuItem("Something else", DEFAULT_DRAFT_ITEM + "+is:mergeable"));
-    prefs.my.add(new MenuItem("Drafts", DEFAULT_DRAFT_ITEM));
-    prefs.my.add(new MenuItem("Totally not drafts", DEFAULT_DRAFT_ITEM));
+    prefs.my.add(0, new MenuItem("Something else", DEFAULT_DRAFT_ITEMS.get(0) + "+is:mergeable"));
+    for (int i = 0; i < DEFAULT_DRAFT_ITEMS.size(); i++) {
+      prefs.my.add(new MenuItem("Draft entry " + i, DEFAULT_DRAFT_ITEMS.get(i)));
+    }
     gApi.accounts().id(accountId.get()).setPreferences(prefs);
 
     List<String> oldNames =
         ImmutableList.<String>builder()
             .add("Something else")
             .addAll(defaultNames)
-            .add("Drafts")
-            .add("Totally not drafts")
+            .add("Draft entry 0")
+            .add("Draft entry 1")
+            .add("Draft entry 2")
+            .add("Draft entry 3")
             .build();
-    assertThat(myMenusFromApi(accountId).keySet()).containsExactlyElementsIn(oldNames).inOrder();
+    assertThat(myMenusFromApi(accountId)).containsExactlyElementsIn(oldNames).inOrder();
 
     schema160.migrateData(db, new TestUpdateUI());
     accountCache.evict(accountId);
+    accountIndexer.index(accountId);
     testEnv.setApiUser(accountId);
 
     assertThat(metaRef(accountId)).isNotEqualTo(oldMetaId);
 
     List<String> newNames =
         ImmutableList.<String>builder().add("Something else").addAll(defaultNames).build();
-    assertThat(myMenusFromNoteDb(accountId).keySet()).containsExactlyElementsIn(newNames).inOrder();
-    assertThat(myMenusFromApi(accountId).keySet()).containsExactlyElementsIn(newNames).inOrder();
+    assertThat(myMenusFromNoteDb(accountId)).containsExactlyElementsIn(newNames).inOrder();
+    assertThat(myMenusFromApi(accountId)).containsExactlyElementsIn(newNames).inOrder();
+  }
+
+  @Test
+  public void skipNonExistentRefsUsersDefault() throws Exception {
+    assertThat(readRef(REFS_USERS_DEFAULT)).isEmpty();
+    schema160.migrateData(db, new TestUpdateUI());
+    assertThat(readRef(REFS_USERS_DEFAULT)).isEmpty();
+  }
+
+  @Test
+  public void deleteDefaultItem() throws Exception {
+    assertThat(readRef(REFS_USERS_DEFAULT)).isEmpty();
+    ImmutableSet<String> defaultNames = defaultMenusFromApi();
+
+    // Setting *any* preference causes preferences.config to contain the full set of "my" sections.
+    // This mimics real-world behavior prior to the 2.15 upgrade; see Issue 8439 for details.
+    GeneralPreferencesInfo prefs = gApi.config().server().getDefaultPreferences();
+    prefs.signedOffBy = !firstNonNull(prefs.signedOffBy, false);
+    gApi.config().server().setDefaultPreferences(prefs);
+
+    try (Repository repo = repoManager.openRepository(allUsersName)) {
+      Config cfg = new BlobBasedConfig(null, repo, readRef(REFS_USERS_DEFAULT).get(), PREFERENCES);
+      assertThat(cfg.getSubsections("my")).containsExactlyElementsIn(defaultNames).inOrder();
+
+      // Add more defaults directly in git, the SetPreferences endpoint doesn't respect the "my"
+      // field in the input in 2.15 and earlier.
+      cfg.setString("my", "Drafts", "url", "#/q/owner:self+is:draft");
+      cfg.setString("my", "Something else", "url", "#/q/owner:self+is:draft+is:mergeable");
+      cfg.setString("my", "Totally not drafts", "url", "#/q/owner:self+is:draft");
+      new TestRepository<>(repo)
+          .branch(REFS_USERS_DEFAULT)
+          .commit()
+          .add(PREFERENCES, cfg.toText())
+          .create();
+    }
+
+    List<String> oldNames =
+        ImmutableList.<String>builder()
+            .addAll(defaultNames)
+            .add("Drafts")
+            .add("Something else")
+            .add("Totally not drafts")
+            .build();
+    assertThat(defaultMenusFromApi()).containsExactlyElementsIn(oldNames).inOrder();
+
+    schema160.migrateData(db, new TestUpdateUI());
+
+    assertThat(readRef(REFS_USERS_DEFAULT)).isPresent();
+
+    List<String> newNames =
+        ImmutableList.<String>builder().addAll(defaultNames).add("Something else").build();
+    assertThat(myMenusFromNoteDb(VersionedAccountPreferences::forDefault).keySet())
+        .containsExactlyElementsIn(newNames)
+        .inOrder();
+    assertThat(defaultMenusFromApi()).containsExactlyElementsIn(newNames).inOrder();
+  }
+
+  private ImmutableSet<String> myMenusFromNoteDb(Account.Id id) throws Exception {
+    return myMenusFromNoteDb(() -> VersionedAccountPreferences.forUser(id)).keySet();
   }
 
   // Raw config values, bypassing the defaults set by PreferencesConfig.
-  private ImmutableMap<String, String> myMenusFromNoteDb(Account.Id id) throws Exception {
+  private ImmutableMap<String, String> myMenusFromNoteDb(
+      Supplier<VersionedAccountPreferences> prefsSupplier) throws Exception {
     try (Repository repo = repoManager.openRepository(allUsersName)) {
-      VersionedAccountPreferences prefs = VersionedAccountPreferences.forUser(id);
+      VersionedAccountPreferences prefs = prefsSupplier.get();
       prefs.load(repo);
       Config cfg = prefs.getConfig();
       return cfg.getSubsections(MY)
@@ -117,18 +197,27 @@
     }
   }
 
-  private ImmutableMap<String, String> myMenusFromApi(Account.Id id) throws Exception {
-    return gApi.accounts()
-        .id(id.get())
-        .getPreferences()
-        .my
-        .stream()
-        .collect(toImmutableMap(i -> i.name, i -> i.url));
+  private ImmutableSet<String> myMenusFromApi(Account.Id id) throws Exception {
+    return myMenus(gApi.accounts().id(id.get()).getPreferences()).keySet();
+  }
+
+  private ImmutableSet<String> defaultMenusFromApi() throws Exception {
+    return myMenus(gApi.config().server().getDefaultPreferences()).keySet();
+  }
+
+  private static ImmutableMap<String, String> myMenus(GeneralPreferencesInfo prefs) {
+
+    return prefs.my.stream().collect(toImmutableMap(i -> i.name, i -> i.url));
   }
 
   private ObjectId metaRef(Account.Id id) throws Exception {
+    return readRef(RefNames.refsUsers(id))
+        .orElseThrow(() -> new AssertionError("missing ref for account " + id));
+  }
+
+  private Optional<ObjectId> readRef(String ref) throws Exception {
     try (Repository repo = repoManager.openRepository(allUsersName)) {
-      return repo.exactRef(RefNames.refsUsers(id)).getObjectId();
+      return Optional.ofNullable(repo.exactRef(ref)).map(Ref::getObjectId);
     }
   }
 }
diff --git a/lib/guava.bzl b/lib/guava.bzl
index 0aa3cf7a..db85900 100644
--- a/lib/guava.bzl
+++ b/lib/guava.bzl
@@ -1,5 +1,5 @@
-GUAVA_VERSION = "23.6-jre"
+GUAVA_VERSION = "24.1-jre"
 
-GUAVA_BIN_SHA1 = "c0b638df79e7b2e1ed98f8d68ac62538a715ab1d"
+GUAVA_BIN_SHA1 = "96c528475465aeb22cce60605d230a7e67cebd7b"
 
 GUAVA_DOC_URL = "https://google.github.io/guava/releases/" + GUAVA_VERSION + "/api/docs/"
diff --git a/lib/jgit/jgit.bzl b/lib/jgit/jgit.bzl
index 71b91a5..cf389850 100644
--- a/lib/jgit/jgit.bzl
+++ b/lib/jgit/jgit.bzl
@@ -1,12 +1,12 @@
 load("//tools/bzl:maven_jar.bzl", "GERRIT", "MAVEN_LOCAL", "MAVEN_CENTRAL", "maven_jar")
 
-_JGIT_VERS = "4.11.0.201803080745-r"
+_JGIT_VERS = "4.11.0.201803080745-r.2-g61e4f1665"
 
-_DOC_VERS = _JGIT_VERS  # Set to _JGIT_VERS unless using a snapshot
+_DOC_VERS = "4.11.0.201803080745-r"  # Set to _JGIT_VERS unless using a snapshot
 
 JGIT_DOC_URL = "http://download.eclipse.org/jgit/site/" + _DOC_VERS + "/apidocs"
 
-_JGIT_REPO = MAVEN_CENTRAL  # Leave here even if set to MAVEN_CENTRAL.
+_JGIT_REPO = GERRIT  # Leave here even if set to MAVEN_CENTRAL.
 
 # set this to use a local version.
 # "/home/<user>/projects/jgit"
@@ -26,28 +26,28 @@
         name = "jgit_lib",
         artifact = "org.eclipse.jgit:org.eclipse.jgit:" + _JGIT_VERS,
         repository = _JGIT_REPO,
-        sha1 = "4ae44a6157e1bc4c5b373be0c274a8f1d9badd76",
-        src_sha1 = "ad6f30f7b7f016a1390f8d289be7da2a9a1f47c5",
+        sha1 = "38489eca0a4308087081d07774af86aa6a50b2ab",
+        src_sha1 = "e43c58829c72b5b18e16d1b2bbd1396ddd93098f",
         unsign = True,
     )
     maven_jar(
         name = "jgit_servlet",
         artifact = "org.eclipse.jgit:org.eclipse.jgit.http.server:" + _JGIT_VERS,
         repository = _JGIT_REPO,
-        sha1 = "687f1d10cfc6424dfbe06acb54b9e67afe2fd917",
+        sha1 = "f5be45e4f97f0bf0825e4ff8fcb2f47588dd7e92",
         unsign = True,
     )
     maven_jar(
         name = "jgit_archive",
         artifact = "org.eclipse.jgit:org.eclipse.jgit.archive:" + _JGIT_VERS,
         repository = _JGIT_REPO,
-        sha1 = "134489ba021e0923735ec85d07f2adde2c8d1e8d",
+        sha1 = "f202f169b2e3a50be90b4123baa941136eda3ed6",
     )
     maven_jar(
         name = "jgit_junit",
         artifact = "org.eclipse.jgit:org.eclipse.jgit.junit:" + _JGIT_VERS,
         repository = _JGIT_REPO,
-        sha1 = "532ad27983c0d77254020ab22d0b2bb8f3d7cd0f",
+        sha1 = "dd9f7e4cc41b4f47591ce51c4752ccfef012c553",
         unsign = True,
     )
 
diff --git a/plugins/replication b/plugins/replication
index f57f029..d8f5bce 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit f57f0297e330660eb699d237cb587d7cc2c0e6b1
+Subproject commit d8f5bcec21492cc21e2499c332298a94ff8defc6
diff --git a/polygerrit-ui/app/behaviors/async-foreach-behavior/async-foreach-behavior.html b/polygerrit-ui/app/behaviors/async-foreach-behavior/async-foreach-behavior.html
index d6d5a86..36e0201 100644
--- a/polygerrit-ui/app/behaviors/async-foreach-behavior/async-foreach-behavior.html
+++ b/polygerrit-ui/app/behaviors/async-foreach-behavior/async-foreach-behavior.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/async-foreach-behavior/async-foreach-behavior_test.html b/polygerrit-ui/app/behaviors/async-foreach-behavior/async-foreach-behavior_test.html
index cbc7056..fec459b 100644
--- a/polygerrit-ui/app/behaviors/async-foreach-behavior/async-foreach-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/async-foreach-behavior/async-foreach-behavior_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/base-url-behavior/base-url-behavior.html b/polygerrit-ui/app/behaviors/base-url-behavior/base-url-behavior.html
index e16d296..48bd10e 100644
--- a/polygerrit-ui/app/behaviors/base-url-behavior/base-url-behavior.html
+++ b/polygerrit-ui/app/behaviors/base-url-behavior/base-url-behavior.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/base-url-behavior/base-url-behavior_test.html b/polygerrit-ui/app/behaviors/base-url-behavior/base-url-behavior_test.html
index 54c8f95..429abe1 100644
--- a/polygerrit-ui/app/behaviors/base-url-behavior/base-url-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/base-url-behavior/base-url-behavior_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/docs-url-behavior/docs-url-behavior.html b/polygerrit-ui/app/behaviors/docs-url-behavior/docs-url-behavior.html
index 07ce55e..64b725f 100644
--- a/polygerrit-ui/app/behaviors/docs-url-behavior/docs-url-behavior.html
+++ b/polygerrit-ui/app/behaviors/docs-url-behavior/docs-url-behavior.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/docs-url-behavior/docs-url-behavior_test.html b/polygerrit-ui/app/behaviors/docs-url-behavior/docs-url-behavior_test.html
index 8154c78..e92eb49 100644
--- a/polygerrit-ui/app/behaviors/docs-url-behavior/docs-url-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/docs-url-behavior/docs-url-behavior_test.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/dom-util-behavior/dom-util-behavior.html b/polygerrit-ui/app/behaviors/dom-util-behavior/dom-util-behavior.html
index 2bc0e67..2d25b29 100644
--- a/polygerrit-ui/app/behaviors/dom-util-behavior/dom-util-behavior.html
+++ b/polygerrit-ui/app/behaviors/dom-util-behavior/dom-util-behavior.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2018 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/dom-util-behavior/dom-util-behavior_test.html b/polygerrit-ui/app/behaviors/dom-util-behavior/dom-util-behavior_test.html
index 96b028c..640d902 100644
--- a/polygerrit-ui/app/behaviors/dom-util-behavior/dom-util-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/dom-util-behavior/dom-util-behavior_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2018 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/gr-access-behavior/gr-access-behavior.html b/polygerrit-ui/app/behaviors/gr-access-behavior/gr-access-behavior.html
index 4e67fda..fb0c685 100644
--- a/polygerrit-ui/app/behaviors/gr-access-behavior/gr-access-behavior.html
+++ b/polygerrit-ui/app/behaviors/gr-access-behavior/gr-access-behavior.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/gr-access-behavior/gr-access-behavior_test.html b/polygerrit-ui/app/behaviors/gr-access-behavior/gr-access-behavior_test.html
index 62992e1..929834f 100644
--- a/polygerrit-ui/app/behaviors/gr-access-behavior/gr-access-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/gr-access-behavior/gr-access-behavior_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/gr-anonymous-name-behavior/gr-anonymous-name-behavior.html b/polygerrit-ui/app/behaviors/gr-anonymous-name-behavior/gr-anonymous-name-behavior.html
index 10065af..e803e54 100644
--- a/polygerrit-ui/app/behaviors/gr-anonymous-name-behavior/gr-anonymous-name-behavior.html
+++ b/polygerrit-ui/app/behaviors/gr-anonymous-name-behavior/gr-anonymous-name-behavior.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/gr-anonymous-name-behavior/gr-anonymous-name-behavior_test.html b/polygerrit-ui/app/behaviors/gr-anonymous-name-behavior/gr-anonymous-name-behavior_test.html
index e4a409b..9f5c445 100644
--- a/polygerrit-ui/app/behaviors/gr-anonymous-name-behavior/gr-anonymous-name-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/gr-anonymous-name-behavior/gr-anonymous-name-behavior_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/gr-change-table-behavior/gr-change-table-behavior.html b/polygerrit-ui/app/behaviors/gr-change-table-behavior/gr-change-table-behavior.html
index 20568e6..d18e442 100644
--- a/polygerrit-ui/app/behaviors/gr-change-table-behavior/gr-change-table-behavior.html
+++ b/polygerrit-ui/app/behaviors/gr-change-table-behavior/gr-change-table-behavior.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/gr-change-table-behavior/gr-change-table-behavior_test.html b/polygerrit-ui/app/behaviors/gr-change-table-behavior/gr-change-table-behavior_test.html
index c265db87c..dc98b59 100644
--- a/polygerrit-ui/app/behaviors/gr-change-table-behavior/gr-change-table-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/gr-change-table-behavior/gr-change-table-behavior_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/gr-list-view-behavior/gr-list-view-behavior.html b/polygerrit-ui/app/behaviors/gr-list-view-behavior/gr-list-view-behavior.html
index 597300e..a82253a 100644
--- a/polygerrit-ui/app/behaviors/gr-list-view-behavior/gr-list-view-behavior.html
+++ b/polygerrit-ui/app/behaviors/gr-list-view-behavior/gr-list-view-behavior.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/gr-list-view-behavior/gr-list-view-behavior_test.html b/polygerrit-ui/app/behaviors/gr-list-view-behavior/gr-list-view-behavior_test.html
index 599f691..54b979f 100644
--- a/polygerrit-ui/app/behaviors/gr-list-view-behavior/gr-list-view-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/gr-list-view-behavior/gr-list-view-behavior_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/gr-patch-set-behavior/gr-patch-set-behavior.html b/polygerrit-ui/app/behaviors/gr-patch-set-behavior/gr-patch-set-behavior.html
index 022d994..d4e83d9 100644
--- a/polygerrit-ui/app/behaviors/gr-patch-set-behavior/gr-patch-set-behavior.html
+++ b/polygerrit-ui/app/behaviors/gr-patch-set-behavior/gr-patch-set-behavior.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/gr-patch-set-behavior/gr-patch-set-behavior_test.html b/polygerrit-ui/app/behaviors/gr-patch-set-behavior/gr-patch-set-behavior_test.html
index 7116c5d..b858c51 100644
--- a/polygerrit-ui/app/behaviors/gr-patch-set-behavior/gr-patch-set-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/gr-patch-set-behavior/gr-patch-set-behavior_test.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior.html b/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior.html
index d3491c7..5e597ae 100644
--- a/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior.html
+++ b/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior_test.html b/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior_test.html
index f48fb98..75c2433 100644
--- a/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/gr-path-list-behavior/gr-path-list-behavior_test.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/gr-tooltip-behavior/gr-tooltip-behavior.html b/polygerrit-ui/app/behaviors/gr-tooltip-behavior/gr-tooltip-behavior.html
index 3e9e19e..07d3484 100644
--- a/polygerrit-ui/app/behaviors/gr-tooltip-behavior/gr-tooltip-behavior.html
+++ b/polygerrit-ui/app/behaviors/gr-tooltip-behavior/gr-tooltip-behavior.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/gr-tooltip-behavior/gr-tooltip-behavior.js b/polygerrit-ui/app/behaviors/gr-tooltip-behavior/gr-tooltip-behavior.js
index 109f534..4d53631 100644
--- a/polygerrit-ui/app/behaviors/gr-tooltip-behavior/gr-tooltip-behavior.js
+++ b/polygerrit-ui/app/behaviors/gr-tooltip-behavior/gr-tooltip-behavior.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function(window) {
   'use strict';
 
diff --git a/polygerrit-ui/app/behaviors/gr-tooltip-behavior/gr-tooltip-behavior_test.html b/polygerrit-ui/app/behaviors/gr-tooltip-behavior/gr-tooltip-behavior_test.html
index a73c9ab..8bca339 100644
--- a/polygerrit-ui/app/behaviors/gr-tooltip-behavior/gr-tooltip-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/gr-tooltip-behavior/gr-tooltip-behavior_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/gr-url-encoding-behavior.html b/polygerrit-ui/app/behaviors/gr-url-encoding-behavior.html
index 99c7c16..365266c 100644
--- a/polygerrit-ui/app/behaviors/gr-url-encoding-behavior.html
+++ b/polygerrit-ui/app/behaviors/gr-url-encoding-behavior.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html b/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html
index bd996760..89f3038 100644
--- a/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html
+++ b/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior_test.html b/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior_test.html
index 6906ea2..8e10302 100644
--- a/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/rest-client-behavior/rest-client-behavior.html b/polygerrit-ui/app/behaviors/rest-client-behavior/rest-client-behavior.html
index 3d6774e..a50f9f7 100644
--- a/polygerrit-ui/app/behaviors/rest-client-behavior/rest-client-behavior.html
+++ b/polygerrit-ui/app/behaviors/rest-client-behavior/rest-client-behavior.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/behaviors/rest-client-behavior/rest-client-behavior_test.html b/polygerrit-ui/app/behaviors/rest-client-behavior/rest-client-behavior_test.html
index 37ec342..b1da281 100644
--- a/polygerrit-ui/app/behaviors/rest-client-behavior/rest-client-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/rest-client-behavior/rest-client-behavior_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.html b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.html
index a92507b..c996474 100644
--- a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.html
+++ b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.js b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.js
index 498cfcf..b6d2955 100644
--- a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.js
+++ b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
@@ -247,4 +250,4 @@
           permission.value);
     },
   });
-})();
\ No newline at end of file
+})();
diff --git a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_test.html b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_test.html
index 44bb594..ea42101 100644
--- a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.html b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.html
index be5cd13..1ad80f5 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.html
+++ b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.js b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.js
index e4f5647..5a463be 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.js
+++ b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list_test.html b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list_test.html
index 06428c7..065a757 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.html b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.html
index bb01897..aa4c465 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.html
+++ b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.js b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.js
index fd3e491..ff6f2d6 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.js
+++ b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
@@ -286,17 +289,23 @@
 
     _computeGroupName(groupId) {
       if (!groupId) { return ''; }
+
       const promises = [];
       this.$.restAPI.getGroupConfig(groupId).then(group => {
+        if (!group || !group.name) { return; }
+
         this._groupName = group.name;
         this.reload();
+
         promises.push(this.$.restAPI.getIsAdmin().then(isAdmin => {
           this._isAdmin = isAdmin;
         }));
+
         promises.push(this.$.restAPI.getIsGroupOwner(group.name).then(
             isOwner => {
               this._groupOwner = isOwner;
             }));
+
         return Promise.all(promises).then(() => {
           this.reload();
         });
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.html b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.html
index 21808fc..a488245 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.html b/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.html
index fdfce5a..0a49016 100644
--- a/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.html
+++ b/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.js b/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.js
index fd30a0b..b5dcf63 100644
--- a/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.js
+++ b/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
@@ -62,4 +65,4 @@
       }
     },
   });
-})();
\ No newline at end of file
+})();
diff --git a/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog_test.html b/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog_test.html
index 8671ad1..d429d7b 100644
--- a/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.html b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.html
index 8bceff1..a652e26 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.html
+++ b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,7 +25,6 @@
 <link rel="import" href="../../core/gr-navigation/gr-navigation.html">
 <link rel="import" href="../../shared/gr-autocomplete/gr-autocomplete.html">
 <link rel="import" href="../../shared/gr-button/gr-button.html">
-<link rel="import" href="../../shared/gr-confirm-dialog/gr-confirm-dialog.html">
 <link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
 <link rel="import" href="../../shared/gr-select/gr-select.html">
 
@@ -55,10 +55,13 @@
           padding: 0 .15em;
         }
       }
+      .hideBranch {
+        display: none;
+      }
     </style>
     <div class="gr-form-styles">
       <div id="form">
-        <section>
+        <section class$="[[_computeBranchClass(baseChange)]]">
           <span class="title">Select branch for new change</span>
           <span class="value">
             <gr-autocomplete
@@ -97,22 +100,12 @@
         <section>
           <label
               class="title"
-              for="privateChangeCheckBox">Private Change</label>
+              for="privateChangeCheckBox">Private change</label>
           <span class="value">
             <input
                 type="checkbox"
                 id="privateChangeCheckBox"
-                checked$="[[_repoConfig.private_by_default.inherited_value]]">
-          </span>
-        </section>
-        <section>
-          <label
-              class="title"
-              for="wipChangeCheckBox">WIP Change</label>
-          <span class="value">
-            <input
-                type="checkbox"
-                id="wipChangeCheckBox">
+                checked$="[[_formatBooleanString(privateByDefault)]]">
           </span>
         </section>
       </div>
diff --git a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.js b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.js
index eace34a..8252d88 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.js
+++ b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
@@ -33,6 +36,8 @@
           return this._getRepoBranchesSuggestions.bind(this);
         },
       },
+      baseChange: String,
+      privateByDefault: String,
       canCreate: {
         type: Boolean,
         notify: true,
@@ -46,8 +51,9 @@
     ],
 
     attached() {
+      if (!this.repoName) { return; }
       this.$.restAPI.getProjectConfig(this.repoName).then(config => {
-        this._repoConfig = config;
+        this.privateByDefault = config.private_by_default;
       });
     },
 
@@ -55,19 +61,21 @@
       '_allowCreate(branch, subject)',
     ],
 
+    _computeBranchClass(baseChange) {
+      return baseChange ? 'hideBranch' : '';
+    },
+
     _allowCreate(branch, subject) {
       this.canCreate = !!branch && !!subject;
     },
 
     handleCreateChange() {
       const isPrivate = this.$.privateChangeCheckBox.checked;
-      const isWip = this.$.wipChangeCheckBox.checked;
+      const isWip = true;
       return this.$.restAPI.createChange(this.repoName, this.branch,
-          this.subject, this.topic, isPrivate, isWip)
+          this.subject, this.topic, isPrivate, isWip, this.baseChange)
           .then(changeCreated => {
-            if (!changeCreated) {
-              return;
-            }
+            if (!changeCreated) { return; }
             Gerrit.Nav.navigateToChange(changeCreated);
           });
     },
@@ -94,5 +102,21 @@
             return branches;
           });
     },
+
+    _formatBooleanString(config) {
+      if (config && config.configured_value === 'TRUE') {
+        return true;
+      } else if (config && config.configured_value === 'FALSE') {
+        return false;
+      } else if (config && config.configured_value === 'INHERIT') {
+        if (config && config.inherited_value) {
+          return true;
+        } else {
+          return false;
+        }
+      } else {
+        return false;
+      }
+    },
   });
 })();
diff --git a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_test.html b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_test.html
index afe3801..08c569c 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -55,9 +56,12 @@
         },
       });
       element = fixture('basic');
-      element.repoName = 'test-repo';
+      element.repoName = 'test-repo',
       element._repoConfig = {
-        private_by_default: {},
+        private_by_default: {
+          configured_value: 'FALSE',
+          inherited_value: false,
+        },
       };
     });
 
@@ -65,18 +69,55 @@
       sandbox.restore();
     });
 
-    test('new change created with private', () => {
-      element._repoConfig = {
-        private_by_default: {
-          inherited_value: true,
-        },
+    test('new change created with default', done => {
+      const configInputObj = {
+        branch: 'test-branch',
+        subject: 'first change created with polygerrit ui',
+        topic: 'test-topic',
+        is_private: false,
+        work_in_progress: true,
       };
 
+      const saveStub = sandbox.stub(element.$.restAPI,
+          'createChange', () => {
+            return Promise.resolve({});
+          });
+
+      element.branch = 'test-branch';
+      element.topic = 'test-topic';
+      element.subject = 'first change created with polygerrit ui';
+      assert.isFalse(element.$.privateChangeCheckBox.checked);
+
+      element.$.branchInput.bindValue = configInputObj.branch;
+      element.$.tagNameInput.bindValue = configInputObj.topic;
+      element.$.messageInput.bindValue = configInputObj.subject;
+
+      element.handleCreateChange().then(() => {
+        // Private change
+        assert.isFalse(saveStub.lastCall.args[4]);
+        // WIP Change
+        assert.isTrue(saveStub.lastCall.args[5]);
+        assert.isTrue(saveStub.called);
+        done();
+      });
+    });
+
+    test('new change created with private', done => {
+      element.privateByDefault = {
+        configured_value: 'TRUE',
+        inherited_value: false,
+      };
+      sandbox.stub(element, '_formatBooleanString', () => {
+        return Promise.resolve(true);
+      });
+      flushAsynchronousOperations();
+
       const configInputObj = {
         branch: 'test-branch',
-        topic: 'test-topic',
         subject: 'first change created with polygerrit ui',
-        work_in_progress: false,
+        topic: 'test-topic',
+        is_private: true,
+        work_in_progress: true,
       };
 
       const saveStub = sandbox.stub(element.$.restAPI,
@@ -94,34 +135,12 @@
       element.$.messageInput.bindValue = configInputObj.subject;
 
       element.handleCreateChange().then(() => {
-        assert.isTrue(saveStub.lastCall.calledWithExactly(configInputObj));
-      });
-    });
-
-    test('new change created with wip', () => {
-      const configInputObj = {
-        branch: 'test-branch',
-        topic: 'test-topic',
-        subject: 'first change created with polygerrit ui',
-      };
-
-      const saveStub = sandbox.stub(element.$.restAPI,
-          'createChange', () => {
-            return Promise.resolve({});
-          });
-
-      element.branch = 'test-branch';
-      element.topic = 'test-topic';
-      element.subject = 'first change created with polygerrit ui';
-      element.$.wipChangeCheckBox.checked = true;
-      assert.isFalse(element.$.privateChangeCheckBox.checked);
-
-      element.$.branchInput.bindValue = configInputObj.branch;
-      element.$.tagNameInput.bindValue = configInputObj.topic;
-      element.$.messageInput.bindValue = configInputObj.subject;
-
-      element.handleCreateChange().then(() => {
-        assert.isTrue(saveStub.lastCall.calledWithExactly(configInputObj));
+        // Private change
+        assert.isTrue(saveStub.lastCall.args[4]);
+        // WIP Change
+        assert.isTrue(saveStub.lastCall.args[5]);
+        assert.isTrue(saveStub.called);
+        done();
       });
     });
 
diff --git a/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.html b/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.html
index 6612e38..0f12e04 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.html
+++ b/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.js b/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.js
index 51024d7..01aeb43 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.js
+++ b/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog_test.html b/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog_test.html
index 7766ea6..95ffdb1 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.html b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.html
index dcc23e1..74c4891 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.html
+++ b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.js b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.js
index a74a7d9..4e9da90 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.js
+++ b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog_test.html b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog_test.html
index c31b5b0..39e200a 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.html b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.html
index 6c78f7c..d1fc822 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.html
+++ b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.js b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.js
index b053310..9dde290 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.js
+++ b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.html b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.html
index f531718..e70c11a 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.html b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.html
index 43c893c..48f4ecc 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.html
+++ b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.js b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.js
index 0bc9a99..b150d68 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.js
+++ b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
@@ -39,17 +42,21 @@
     },
 
     _getAuditLogs() {
-      if (!this.groupId) {
-        return '';
-      }
-      return this.$.restAPI.getGroupAuditLog(this.groupId).then(auditLog => {
-        if (!auditLog) {
-          this._auditLog = [];
-          return;
-        }
-        this._auditLog = auditLog;
-        this._loading = false;
-      });
+      if (!this.groupId) { return ''; }
+
+      const errFn = response => {
+        this.fire('page-error', {response});
+      };
+
+      return this.$.restAPI.getGroupAuditLog(this.groupId, errFn)
+          .then(auditLog => {
+            if (!auditLog) {
+              this._auditLog = [];
+              return;
+            }
+            this._auditLog = auditLog;
+            this._loading = false;
+          });
     },
 
     _status(item) {
@@ -57,9 +64,8 @@
     },
 
     _computeGroupUrl(id) {
-      if (!id) {
-        return '';
-      }
+      if (!id) { return ''; }
+
       return this.getBaseUrl() + '/admin/groups/' + id;
     },
 
diff --git a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_test.html b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_test.html
index b179718..86e8a25 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -34,11 +35,17 @@
 <script>
   suite('gr-group-audit-log tests', () => {
     let element;
+    let sandbox;
 
     setup(() => {
+      sandbox = sinon.sandbox.create();
       element = fixture('basic');
     });
 
+    teardown(() => {
+      sandbox.restore();
+    });
+
     suite('members', () => {
       test('test getNameForMember', () => {
         let account = {
@@ -117,5 +124,24 @@
         assert.equal(element._getNameForUser(account.user), 'test-email');
       });
     });
+
+    suite('404', () => {
+      test('fires page-error', done => {
+        element.groupId = 1;
+
+        const response = {status: 404};
+        sandbox.stub(
+            element.$.restAPI, 'getGroupAuditLog', (group, errFn) => {
+              errFn(response);
+            });
+
+        element.addEventListener('page-error', e => {
+          assert.deepEqual(e.detail.response, response);
+          done();
+        });
+
+        element._getAuditLogs();
+      });
+    });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.html b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.html
index 6633538..f2b8855 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.html
+++ b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.js b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.js
index 5257e69..553856a 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.js
+++ b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
@@ -75,9 +78,13 @@
 
       const promises = [];
 
-      return this.$.restAPI.getGroupConfig(this.groupId).then(
-          config => {
-            if (!config.name) { return; }
+      const errFn = response => {
+        this.fire('page-error', {response});
+      };
+
+      return this.$.restAPI.getGroupConfig(this.groupId, errFn)
+          .then(config => {
+            if (!config || !config.name) { return Promise.resolve(); }
 
             this._groupName = config.name;
 
diff --git a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_test.html b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_test.html
index d670d4d..ca854c0 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -38,9 +39,11 @@
     let groups;
     let groupMembers;
     let includedGroups;
+    let groupStub;
 
     setup(() => {
       sandbox = sinon.sandbox.create();
+
       groups = {
         name: 'Administrators',
         owner: 'Administrators',
@@ -118,9 +121,6 @@
         getConfig() {
           return Promise.resolve();
         },
-        getGroupConfig() {
-          return Promise.resolve(groups);
-        },
         getGroupMembers() {
           return Promise.resolve(groupMembers);
         },
@@ -137,6 +137,9 @@
       element = fixture('basic');
       sandbox.stub(element, 'getBaseUrl').returns('https://test/site');
       element.groupId = 1;
+      groupStub = sandbox.stub(element.$.restAPI, 'getGroupConfig', () => {
+        return Promise.resolve(groups);
+      });
       return element._loadGroupDetails();
     });
 
@@ -251,5 +254,29 @@
       assert.equal(element._itemId, '1000098');
       assert.equal(element._itemName, '1000098');
     });
+
+    test('_computeLoadingClass', () => {
+      assert.equal(element._computeLoadingClass(true), 'loading');
+
+      assert.equal(element._computeLoadingClass(false), '');
+    });
+
+    test('fires page-error', done => {
+      groupStub.restore();
+
+      element.groupId = 1;
+
+      const response = {status: 404};
+      sandbox.stub(
+          element.$.restAPI, 'getGroupConfig', (group, errFn) => {
+            errFn(response);
+          });
+      element.addEventListener('page-error', e => {
+        assert.deepEqual(e.detail.response, response);
+        done();
+      });
+
+      element._loadGroupDetails();
+    });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/admin/gr-group/gr-group.html b/polygerrit-ui/app/elements/admin/gr-group/gr-group.html
index 33866d3..21978d5 100644
--- a/polygerrit-ui/app/elements/admin/gr-group/gr-group.html
+++ b/polygerrit-ui/app/elements/admin/gr-group/gr-group.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-group/gr-group.js b/polygerrit-ui/app/elements/admin/gr-group/gr-group.js
index d975675..1e16720 100644
--- a/polygerrit-ui/app/elements/admin/gr-group/gr-group.js
+++ b/polygerrit-ui/app/elements/admin/gr-group/gr-group.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
@@ -95,18 +98,26 @@
     _loadGroup() {
       if (!this.groupId) { return; }
 
-      return this.$.restAPI.getGroupConfig(this.groupId).then(
-          config => {
+      const promises = [];
+
+      const errFn = response => {
+        this.fire('page-error', {response});
+      };
+
+      return this.$.restAPI.getGroupConfig(this.groupId, errFn)
+          .then(config => {
+            if (!config || !config.name) { return Promise.resolve(); }
+
             this._groupName = config.name;
 
-            this.$.restAPI.getIsAdmin().then(isAdmin => {
+            promises.push(this.$.restAPI.getIsAdmin().then(isAdmin => {
               this._isAdmin = isAdmin ? true : false;
-            });
+            }));
 
-            this.$.restAPI.getIsGroupOwner(config.name)
+            promises.push(this.$.restAPI.getIsGroupOwner(config.name)
                 .then(isOwner => {
                   this._groupOwner = isOwner ? true : false;
-                });
+                }));
 
             // If visible to all is undefined, set to false. If it is defined
             // as false, setting to false is fine. If any optional values
@@ -119,7 +130,9 @@
 
             this.fire('title-change', {title: config.name});
 
-            this._loading = false;
+            return Promise.all(promises).then(() => {
+              this._loading = false;
+            });
           });
     },
 
diff --git a/polygerrit-ui/app/elements/admin/gr-group/gr-group_test.html b/polygerrit-ui/app/elements/admin/gr-group/gr-group_test.html
index 16a6261..4ee7414a 100644
--- a/polygerrit-ui/app/elements/admin/gr-group/gr-group_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-group/gr-group_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -35,25 +36,28 @@
   suite('gr-group tests', () => {
     let element;
     let sandbox;
+    let groupStub;
+    const group = {
+      id: '6a1e70e1a88782771a91808c8af9bbb7a9871389',
+      url: '#/admin/groups/uuid-6a1e70e1a88782771a91808c8af9bbb7a9871389',
+      options: {
+      },
+      description: 'Gerrit Site Administrators',
+      group_id: 1,
+      owner: 'Administrators',
+      owner_id: '6a1e70e1a88782771a91808c8af9bbb7a9871389',
+      name: 'Administrators',
+    };
 
     setup(() => {
       sandbox = sinon.sandbox.create();
       stub('gr-rest-api-interface', {
         getLoggedIn() { return Promise.resolve(true); },
-        getGroupConfig() {
-          return Promise.resolve({
-            id: '6a1e70e1a88782771a91808c8af9bbb7a9871389',
-            url: '#/admin/groups/uuid-6a1e70e1a88782771a91808c8af9bbb7a9871389',
-            options: {
-            },
-            description: 'Gerrit Site Administrators',
-            group_id: 1,
-            owner: 'Administrators',
-            owner_id: '6a1e70e1a88782771a91808c8af9bbb7a9871389',
-          });
-        },
       });
       element = fixture('basic');
+      groupStub = sandbox.stub(element.$.restAPI, 'getGroupConfig', () => {
+        return Promise.resolve(group);
+      });
     });
 
     teardown(() => {
@@ -117,6 +121,30 @@
       });
     });
 
+    test('test for undefined group name', done => {
+      groupStub.restore();
+
+      sandbox.stub(element.$.restAPI, 'getGroupConfig', () => {
+        return Promise.resolve({});
+      });
+
+      assert.isUndefined(element.groupId);
+
+      element.groupId = 1;
+
+      assert.isDefined(element.groupId);
+
+      // Test that loading shows instead of filling
+      // in group details
+      element._loadGroup().then(() => {
+        assert.isTrue(element.$.loading.classList.contains('loading'));
+
+        assert.isTrue(element._loading);
+
+        done();
+      });
+    });
+
     test('test fire event', done => {
       element._groupConfig = {
         name: 'test-group',
@@ -156,5 +184,29 @@
       const owner = false;
       assert.equal(element._computeGroupDisabled(owner, admin), true);
     });
+
+    test('_computeLoadingClass', () => {
+      assert.equal(element._computeLoadingClass(true), 'loading');
+      assert.equal(element._computeLoadingClass(false), '');
+    });
+
+    test('fires page-error', done => {
+      groupStub.restore();
+
+      element.groupId = 1;
+
+      const response = {status: 404};
+      sandbox.stub(
+          element.$.restAPI, 'getGroupConfig', (group, errFn) => {
+            errFn(response);
+          });
+
+      element.addEventListener('page-error', e => {
+        assert.deepEqual(e.detail.response, response);
+        done();
+      });
+
+      element._loadGroup();
+    });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.html b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.html
index d726feb..cc0ca51 100644
--- a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.html
+++ b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.js b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.js
index 41d7896..01caf1d 100644
--- a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.js
+++ b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
@@ -252,4 +255,4 @@
       this.dispatchEvent(new CustomEvent('access-modified', {bubbles: true}));
     },
   });
-})();
\ No newline at end of file
+})();
diff --git a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_test.html b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_test.html
index dc00abf..6799d10 100644
--- a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.html b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.html
index 57cc771..9e4396a 100644
--- a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.html
+++ b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.js b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.js
index d441407..1bcbcaa 100644
--- a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.js
+++ b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list_test.html b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list_test.html
index fea8069..5752aa1 100644
--- a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.html b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.html
index c887367..c15df90 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -78,7 +79,7 @@
           </template>
         </div>
         <gr-button id="editBtn"
-            class$="[[_computeShowEditClass(_sections)]]"
+            class="visible"
             on-tap="_handleEdit">[[_editOrCancel(_editing)]]</gr-button>
         <gr-button id="saveBtn"
             primary
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.js b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.js
index 2bebb96..a8d21e2 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
@@ -126,25 +129,40 @@
      */
     _repoChanged(repo) {
       if (!repo) { return Promise.resolve(); }
+
       const promises = [];
+
+      const errFn = response => {
+        this.fire('page-error', {response});
+      };
+
       // Always reset sections when a project changes.
       this._sections = [];
-      promises.push(this.$.restAPI.getRepoAccessRights(repo).then(res => {
-        this._inheritsFrom = res.inherits_from;
-        this._local = res.local;
-        this._groups = res.groups;
-        this._weblinks = res.config_web_links || [];
-        this._canUpload = res.can_upload;
-        return this.toSortedArray(this._local);
-      }));
+      promises.push(this.$.restAPI.getRepoAccessRights(repo, errFn)
+          .then(res => {
+            if (!res) { return Promise.resolve(); }
 
-      promises.push(this.$.restAPI.getCapabilities().then(res => {
-        return res;
-      }));
+            this._inheritsFrom = res.inherits_from;
+            this._local = res.local;
+            this._groups = res.groups;
+            this._weblinks = res.config_web_links || [];
+            this._canUpload = res.can_upload;
+            return this.toSortedArray(this._local);
+          }));
 
-      promises.push(this.$.restAPI.getRepo(repo).then(res => {
-        return res.labels;
-      }));
+      promises.push(this.$.restAPI.getCapabilities(errFn)
+          .then(res => {
+            if (!res) { return Promise.resolve(); }
+
+            return res;
+          }));
+
+      promises.push(this.$.restAPI.getRepo(repo, errFn)
+          .then(res => {
+            if (!res) { return Promise.resolve(); }
+
+            return res.labels;
+          }));
 
       promises.push(this.$.restAPI.getIsAdmin().then(isAdmin => {
         this._isAdmin = isAdmin;
@@ -316,11 +334,6 @@
       });
     },
 
-    _computeShowEditClass(sections) {
-      if (!sections.length) { return ''; }
-      return 'visible';
-    },
-
     _computeShowSaveClass(editing) {
       if (!editing) { return ''; }
       return 'visible';
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.html b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.html
index 242662c..988fc7c 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -217,6 +218,22 @@
       assert.equal(element._computeLoadingClass(false), '');
     });
 
+    test('fires page-error', done => {
+      const response = {status: 404};
+
+      sandbox.stub(
+          element.$.restAPI, 'getRepoAccessRights', (repoName, errFn) => {
+            errFn(response);
+          });
+
+      element.addEventListener('page-error', e => {
+        assert.deepEqual(e.detail.response, response);
+        done();
+      });
+
+      element.repo = 'test';
+    });
+
     suite('with defined sections', () => {
       const testEditSaveCancelBtns = () => {
         // Edit button is visible and Save button is hidden.
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-command/gr-repo-command.html b/polygerrit-ui/app/elements/admin/gr-repo-command/gr-repo-command.html
index 0b065bc..f42652d 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-command/gr-repo-command.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo-command/gr-repo-command.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-command/gr-repo-command.js b/polygerrit-ui/app/elements/admin/gr-repo-command/gr-repo-command.js
index ce9655c..e49c4de 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-command/gr-repo-command.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-command/gr-repo-command.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-command/gr-repo-command_test.html b/polygerrit-ui/app/elements/admin/gr-repo-command/gr-repo-command_test.html
index 5ec2ef9..9f9ac92 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-command/gr-repo-command_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo-command/gr-repo-command_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.html b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.html
index 41e1c15..b686237 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.js b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.js
index d554f4d..a25055e 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
@@ -47,10 +50,17 @@
     _loadRepo() {
       if (!this.repo) { return Promise.resolve(); }
 
-      return this.$.restAPI.getProjectConfig(this.repo).then(config => {
-        this._repoConfig = config;
-        this._loading = false;
-      });
+      const errFn = response => {
+        this.fire('page-error', {response});
+      };
+
+      return this.$.restAPI.getProjectConfig(this.repo, errFn)
+          .then(config => {
+            if (!config) { return Promise.resolve(); }
+
+            this._repoConfig = config;
+            this._loading = false;
+          });
     },
 
     _computeLoadingClass(loading) {
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_test.html b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_test.html
index 762089f..76c65e8 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -36,13 +37,14 @@
   suite('gr-repo-commands tests', () => {
     let element;
     let sandbox;
+    let repoStub;
 
     setup(() => {
       sandbox = sinon.sandbox.create();
-      stub('gr-rest-api-interface', {
-        getProjectConfig() { return Promise.resolve({}); },
-      });
       element = fixture('basic');
+      repoStub = sandbox.stub(element.$.restAPI, 'getProjectConfig', () => {
+        return Promise.resolve({});
+      });
     });
 
     teardown(() => {
@@ -113,5 +115,25 @@
         });
       });
     });
+
+    suite('404', () => {
+      test('fires page-error', done => {
+        repoStub.restore();
+
+        element.repo = 'test';
+
+        const response = {status: 404};
+        sandbox.stub(
+            element.$.restAPI, 'getProjectConfig', (repo, errFn) => {
+              errFn(response);
+            });
+        element.addEventListener('page-error', e => {
+          assert.deepEqual(e.detail.response, response);
+          done();
+        });
+
+        element._loadRepo();
+      });
+    });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.html b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.html
index f1a979c..fdbc239 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2018 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.js b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.js
index bbdf92f..a4c2c03 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
@@ -32,7 +35,14 @@
     _repoChanged(repo) {
       this._loading = true;
       if (!repo) { return Promise.resolve(); }
-      this.$.restAPI.getRepoDashboards(this.repo).then(res => {
+
+      const errFn = response => {
+        this.fire('page-error', {response});
+      };
+
+      this.$.restAPI.getRepoDashboards(this.repo, errFn).then(res => {
+        if (!res) { return Promise.resolve(); }
+
         // Flatten 2 dimenional array, and sort by id.
         const dashboards = res.concat.apply([], res).sort((a, b) =>
             a.id > b.id);
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards_test.html b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards_test.html
index bb886c7..bd4019e 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -241,5 +242,22 @@
         });
       });
     });
+
+    suite('404', () => {
+      test('fires page-error', done => {
+        const response = {status: 404};
+        sandbox.stub(
+            element.$.restAPI, 'getRepoDashboards', (repo, errFn) => {
+              errFn(response);
+            });
+
+        element.addEventListener('page-error', e => {
+          assert.deepEqual(e.detail.response, response);
+          done();
+        });
+
+        element.repo = 'test';
+      });
+    });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.html b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.html
index e8dde77..d57dd329 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.js b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.js
index 3cf0b9b..eaad353 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_test.html b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_test.html
index 83b086e..6f75805 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.html b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.html
index a43667a..6c1f8fb 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.js b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.js
index 0686a67..2c0a737 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_test.html b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_test.html
index 46c0951..731437fa 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.html b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.html
index b1964ff..3eb9d62 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,6 +19,7 @@
 <link rel="import" href="../../../bower_components/iron-autogrow-textarea/iron-autogrow-textarea.html">
 <link rel="import" href="../../../bower_components/iron-input/iron-input.html">
 
+<link rel="import" href="../../plugins/gr-endpoint-decorator/gr-endpoint-decorator.html">
 <link rel="import" href="../../shared/gr-download-commands/gr-download-commands.html">
 <link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
 <link rel="import" href="../../shared/gr-select/gr-select.html">
@@ -321,6 +323,9 @@
                 on-tap="_handleSaveRepoConfig"
                 disabled$="[[_computeButtonDisabled(_readOnly, _configChanged)]]">Save changes</gr-button>
           </fieldset>
+          <gr-endpoint-decorator name="repo-config">
+            <gr-endpoint-param name="repoName" value="[[repo]]"></gr-endpoint-param>
+          </gr-endpoint-decorator>
         </div>
       </div>
     </main>
diff --git a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.js b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.js
index 2febb25..94b9e3f 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
@@ -118,18 +121,27 @@
       if (!this.repo) { return Promise.resolve(); }
 
       const promises = [];
+
+      const errFn = response => {
+        this.fire('page-error', {response});
+      };
+
       promises.push(this._getLoggedIn().then(loggedIn => {
         this._loggedIn = loggedIn;
         if (loggedIn) {
           this.$.restAPI.getRepoAccess(this.repo).then(access => {
+            if (!access) { return Promise.resolve(); }
+
             // If the user is not an owner, is_owner is not a property.
             this._readOnly = !access[this.repo].is_owner;
           });
         }
       }));
 
-      promises.push(this.$.restAPI.getProjectConfig(this.repo).then(
-          config => {
+      promises.push(this.$.restAPI.getProjectConfig(this.repo, errFn)
+          .then(config => {
+            if (!config) { return Promise.resolve(); }
+
             if (config.default_submit_type) {
               // The gr-select is bound to submit_type, which needs to be the
               // *configured* submit type. When default_submit_type is
@@ -147,6 +159,8 @@
           }));
 
       promises.push(this.$.restAPI.getConfig().then(config => {
+        if (!config) { return Promise.resolve(); }
+
         this._schemesObj = config.download.schemes;
         this._noteDbEnabled = !!config.note_db_enabled;
       }));
diff --git a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_test.html b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_test.html
index 9ea0177..d6d4366 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -35,6 +36,66 @@
   suite('gr-repo tests', () => {
     let element;
     let sandbox;
+    let repoStub;
+    const repoConf = {
+      description: 'Access inherited by all other projects.',
+      use_contributor_agreements: {
+        value: false,
+        configured_value: 'FALSE',
+      },
+      use_content_merge: {
+        value: false,
+        configured_value: 'FALSE',
+      },
+      use_signed_off_by: {
+        value: false,
+        configured_value: 'FALSE',
+      },
+      create_new_change_for_all_not_in_target: {
+        value: false,
+        configured_value: 'FALSE',
+      },
+      require_change_id: {
+        value: false,
+        configured_value: 'FALSE',
+      },
+      enable_signed_push: {
+        value: false,
+        configured_value: 'FALSE',
+      },
+      require_signed_push: {
+        value: false,
+        configured_value: 'FALSE',
+      },
+      reject_implicit_merges: {
+        value: false,
+        configured_value: 'FALSE',
+      },
+      private_by_default: {
+        value: false,
+        configured_value: 'FALSE',
+      },
+      match_author_to_committer_date: {
+        value: false,
+        configured_value: 'FALSE',
+      },
+      reject_empty_commit: {
+        value: false,
+        configured_value: 'FALSE',
+      },
+      enable_reviewer_by_email: {
+        value: false,
+        configured_value: 'FALSE',
+      },
+      max_object_size_limit: {},
+      submit_type: 'MERGE_IF_NECESSARY',
+      default_submit_type: {
+        value: 'MERGE_IF_NECESSARY',
+        configured_value: 'INHERIT',
+        inherited_value: 'MERGE_IF_NECESSARY',
+      },
+    };
+
     const REPO = 'test-repo';
     const SCHEMES = {http: {}, repo: {}, ssh: {}};
 
@@ -50,71 +111,14 @@
       sandbox = sinon.sandbox.create();
       stub('gr-rest-api-interface', {
         getLoggedIn() { return Promise.resolve(false); },
-        getProjectConfig() {
-          return Promise.resolve({
-            description: 'Access inherited by all other projects.',
-            use_contributor_agreements: {
-              value: false,
-              configured_value: 'FALSE',
-            },
-            use_content_merge: {
-              value: false,
-              configured_value: 'FALSE',
-            },
-            use_signed_off_by: {
-              value: false,
-              configured_value: 'FALSE',
-            },
-            create_new_change_for_all_not_in_target: {
-              value: false,
-              configured_value: 'FALSE',
-            },
-            require_change_id: {
-              value: false,
-              configured_value: 'FALSE',
-            },
-            enable_signed_push: {
-              value: false,
-              configured_value: 'FALSE',
-            },
-            require_signed_push: {
-              value: false,
-              configured_value: 'FALSE',
-            },
-            reject_implicit_merges: {
-              value: false,
-              configured_value: 'FALSE',
-            },
-            private_by_default: {
-              value: false,
-              configured_value: 'FALSE',
-            },
-            match_author_to_committer_date: {
-              value: false,
-              configured_value: 'FALSE',
-            },
-            reject_empty_commit: {
-              value: false,
-              configured_value: 'FALSE',
-            },
-            enable_reviewer_by_email: {
-              value: false,
-              configured_value: 'FALSE',
-            },
-            max_object_size_limit: {},
-            submit_type: 'MERGE_IF_NECESSARY',
-            default_submit_type: {
-              value: 'MERGE_IF_NECESSARY',
-              configured_value: 'INHERIT',
-              inherited_value: 'MERGE_IF_NECESSARY',
-            },
-          });
-        },
         getConfig() {
           return Promise.resolve({download: {}});
         },
       });
       element = fixture('basic');
+      repoStub = sandbox.stub(element.$.restAPI, 'getProjectConfig', () => {
+        return Promise.resolve(repoConf);
+      });
     });
 
     teardown(() => {
@@ -230,6 +234,24 @@
       ]);
     });
 
+    test('fires page-error', done => {
+      repoStub.restore();
+
+      element.repo = 'test';
+
+      const response = {status: 404};
+      sandbox.stub(
+          element.$.restAPI, 'getProjectConfig', (repo, errFn) => {
+            errFn(response);
+          });
+      element.addEventListener('page-error', e => {
+        assert.deepEqual(e.detail.response, response);
+        done();
+      });
+
+      element._loadRepo();
+    });
+
     suite('admin', () => {
       setup(() => {
         element.repo = REPO;
diff --git a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.html b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.html
index 06f567c..2d05a3b 100644
--- a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.html
+++ b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.js b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.js
index a3b0272..0a719be 100644
--- a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.js
+++ b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
@@ -216,4 +219,4 @@
       this._originalRuleValues = Object.assign({}, value);
     },
   });
-})();
\ No newline at end of file
+})();
diff --git a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_test.html b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_test.html
index 7595eb1..864bf16 100644
--- a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.html b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.html
index 46ff469..6005b92 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.html
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -85,7 +86,9 @@
         display: none;
       }
       .size gr-tooltip-content {
+        margin: -.4rem -.6rem;
         max-width: 2.5rem;
+        padding: .4rem .6rem;
       }
       a {
         color: var(--default-text-color);
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js
index 9675f9a..259580b 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.html b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.html
index 4ac7b8e..81e1034 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.html
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.html b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.html
index ec0e5a2..8035df59 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.html
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.js b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.js
index f5de254..e4af24d 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.js
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view_test.html b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view_test.html
index c0b1b81..2091c7d 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view_test.html
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.html b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.html
index ec8ab2d..1e0622e 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.html
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js
index 3489db0..89c6577 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
@@ -285,10 +288,13 @@
     },
 
     _handleRKey(e) {
-      if (this.shouldSuppressKeyboardShortcut(e) ||
-          this.modifierPressed(e)) { return; }
+      if (this.shouldSuppressKeyboardShortcut(e)) { return; }
 
       e.preventDefault();
+      this._reloadWindow();
+    },
+
+    _reloadWindow() {
       window.location.reload();
     },
 
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html
index aed48e3..e72830c 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -190,6 +191,10 @@
         MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
         assert.equal(element.selectedIndex, 0);
 
+        const reloadStub = sandbox.stub(element, '_reloadWindow');
+        MockInteractions.pressAndReleaseKeyOn(element, 82, 'shift', 'r');
+        assert.isTrue(reloadStub.called);
+
         done();
       });
     });
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.html b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.html
index e129cee..33cd39e 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.html
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.js b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.js
index cce291b..6be2331 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.js
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.html b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.html
index 5621f9c..a3aa4f2 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.html
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.html b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.html
index d3d0736..1c19ab2 100644
--- a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.html
+++ b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.js b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.js
index d09e865..cf5fefd 100644
--- a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.js
+++ b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header_test.html b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header_test.html
index 4ae8db4..c33be3b 100644
--- a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header_test.html
+++ b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-account-entry/gr-account-entry.html b/polygerrit-ui/app/elements/change/gr-account-entry/gr-account-entry.html
index 9805d8e..025ff79 100644
--- a/polygerrit-ui/app/elements/change/gr-account-entry/gr-account-entry.html
+++ b/polygerrit-ui/app/elements/change/gr-account-entry/gr-account-entry.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -38,6 +39,7 @@
         allow-non-suggested-values="[[allowAnyInput]]"
         on-commit="_handleInputCommit"
         clear-on-commit
+        no-debounce
         warn-uncommitted
         text="{{_inputText}}">
     </gr-autocomplete>
diff --git a/polygerrit-ui/app/elements/change/gr-account-entry/gr-account-entry.js b/polygerrit-ui/app/elements/change/gr-account-entry/gr-account-entry.js
index 79ac07b..6a3ea54 100644
--- a/polygerrit-ui/app/elements/change/gr-account-entry/gr-account-entry.js
+++ b/polygerrit-ui/app/elements/change/gr-account-entry/gr-account-entry.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/change/gr-account-entry/gr-account-entry_test.html b/polygerrit-ui/app/elements/change/gr-account-entry/gr-account-entry_test.html
index 0d2d859..07c1554 100644
--- a/polygerrit-ui/app/elements/change/gr-account-entry/gr-account-entry_test.html
+++ b/polygerrit-ui/app/elements/change/gr-account-entry/gr-account-entry_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-account-list/gr-account-list.html b/polygerrit-ui/app/elements/change/gr-account-list/gr-account-list.html
index 379dfce..1bfc5eb 100644
--- a/polygerrit-ui/app/elements/change/gr-account-list/gr-account-list.html
+++ b/polygerrit-ui/app/elements/change/gr-account-list/gr-account-list.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-account-list/gr-account-list.js b/polygerrit-ui/app/elements/change/gr-account-list/gr-account-list.js
index a8c3e2b..950c1e8 100644
--- a/polygerrit-ui/app/elements/change/gr-account-list/gr-account-list.js
+++ b/polygerrit-ui/app/elements/change/gr-account-list/gr-account-list.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/change/gr-account-list/gr-account-list_test.html b/polygerrit-ui/app/elements/change/gr-account-list/gr-account-list_test.html
index 7097b86..544238b 100644
--- a/polygerrit-ui/app/elements/change/gr-account-list/gr-account-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-account-list/gr-account-list_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
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 322de71..d097d01 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
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,6 +20,7 @@
 <link rel="import" href="../../../behaviors/gr-patch-set-behavior/gr-patch-set-behavior.html">
 <link rel="import" href="../../../behaviors/rest-client-behavior/rest-client-behavior.html">
 <link rel="import" href="../../../bower_components/iron-input/iron-input.html">
+<link rel="import" href="../../admin/gr-create-change-dialog/gr-create-change-dialog.html">
 <link rel="import" href="../../core/gr-navigation/gr-navigation.html">
 <link rel="import" href="../../core/gr-reporting/gr-reporting.html">
 <link rel="import" href="../../shared/gr-button/gr-button.html">
@@ -160,6 +162,23 @@
           on-confirm="_handleAbandonDialogConfirm"
           on-cancel="_handleConfirmDialogCancel"
           hidden></gr-confirm-abandon-dialog>
+      <gr-confirm-dialog id="createFollowUpDialog"
+          class="confirmDialog"
+          confirm-label="Create"
+          on-confirm="_handleCreateFollowUpChange"
+          on-cancel="_handleCloseCreateFollowUpChange">
+        <div class="header" slot="header">
+          Create Follow-Up Change
+        </div>
+        <div class="main" slot="main">
+          <gr-create-change-dialog
+              id="createFollowUpChange"
+              branch="[[change.branch]]"
+              base-change="[[change.id]]"
+              repo-name="[[change.project]]"
+              private-by-default="[[privateByDefault]]"></gr-create-change-dialog>
+        </div>
+      </gr-confirm-dialog>
       <gr-confirm-dialog
           id="confirmDeleteDialog"
           class="confirmDialog"
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 adab1c8..5c27757 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
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
@@ -53,6 +56,7 @@
     DELETE: '/',
     DELETE_EDIT: 'deleteEdit',
     EDIT: 'edit',
+    FOLLOW_UP: 'followup',
     IGNORE: 'ignore',
     MOVE: 'move',
     PRIVATE: 'private',
@@ -193,7 +197,14 @@
      */
 
     properties: {
-      /** @type {{ _number: number, branch: string, project: string }} */
+      /**
+       * @type {{
+       *    _number: number,
+       *    branch: string,
+       *    id: string,
+       *    project: string,
+       *  }}
+       */
       change: Object,
       actions: {
         type: Object,
@@ -232,6 +243,7 @@
         type: Object,
         value() { return {}; },
       },
+      privateByDefault: String,
 
       _loading: {
         type: Boolean,
@@ -308,6 +320,10 @@
               type: ActionType.CHANGE,
               key: ChangeActions.PRIVATE_DELETE,
             },
+            {
+              type: ActionType.CHANGE,
+              key: ChangeActions.FOLLOW_UP,
+            },
           ];
           return value;
         },
@@ -860,6 +876,9 @@
         case ChangeActions.DELETE_EDIT:
           this._handleDeleteEditTap();
           break;
+        case ChangeActions.FOLLOW_UP:
+          this._handleFollowUpTap();
+          break;
         case ChangeActions.WIP:
           this._handleWipTap();
           break;
@@ -997,6 +1016,15 @@
           {message: el.message});
     },
 
+    _handleCreateFollowUpChange() {
+      this.$.createFollowUpChange.handleCreateChange();
+      this._handleCloseCreateFollowUpChange();
+    },
+
+    _handleCloseCreateFollowUpChange() {
+      this.$.overlay.close();
+    },
+
     _handleDeleteConfirm() {
       this._fireAction('/', this.actions[ChangeActions.DELETE], false);
     },
@@ -1185,6 +1213,10 @@
       this._showActionDialog(this.$.confirmDeleteEditDialog);
     },
 
+    _handleFollowUpTap() {
+      this._showActionDialog(this.$.createFollowUpDialog);
+    },
+
     _handleWipTap() {
       this._fireAction('/wip', this.actions.wip, false);
     },
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 835d560..ca6337a 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
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata-it_test.html b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata-it_test.html
index 90776c0..9d51339 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata-it_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata-it_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.html b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.html
index 66ab290..eae9d2e 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.html
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js
index ddee577..8947e0e 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.html b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.html
index 9ee09ea..68b838f 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
index 419fb56..42404aa 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -44,6 +45,7 @@
 <link rel="import" href="../gr-download-dialog/gr-download-dialog.html">
 <link rel="import" href="../gr-file-list-header/gr-file-list-header.html">
 <link rel="import" href="../gr-file-list/gr-file-list.html">
+<link rel="import" href="../gr-included-in-dialog/gr-included-in-dialog.html">
 <link rel="import" href="../gr-messages-list/gr-messages-list.html">
 <link rel="import" href="../gr-related-changes-list/gr-related-changes-list.html">
 <link rel="import" href="../gr-reply-dialog/gr-reply-dialog.html">
@@ -110,11 +112,6 @@
       .changeStatus {
         text-transform: capitalize;
       }
-      .container {
-        /* Needed to restrict the change view from allowing horizontal
-          scrolling */
-        width: 100vw;
-      }
       /* Strong specificity here is needed due to
          https://github.com/Polymer/polymer/issues/2531 */
       .container section.changeInfo {
@@ -261,6 +258,9 @@
       #messageList.visible {
         display: block;
       }
+      #includedInOverlay {
+        width: 65em;
+      }
       @media screen and (min-width: 80em) {
         .commitMessage {
           max-width: var(--commit-message-max-width, 100ch);
@@ -395,6 +395,7 @@
               edit-patchset-loaded="[[hasEditPatchsetLoaded(_patchRange.*)]]"
               edit-mode="[[_editMode]]"
               edit-based-on-current-patch-set="[[hasEditBasedOnCurrentPatchSet(_allPatchSets)]]"
+              private-by-default="[[_projectConfig.private_by_default]]"
               on-reload-change="_handleReloadChange"
               on-edit-tap="_handleEditTap"
               on-stop-edit-tap="_handleStopEditTap"
@@ -518,6 +519,7 @@
             files-expanded="[[_filesExpanded]]"
             on-open-diff-prefs="_handleOpenDiffPrefs"
             on-open-download-dialog="_handleOpenDownloadDialog"
+            on-open-included-in-dialog="_handleOpenIncludedInDialog"
             on-expand-diffs="_expandAllDiffs"
             on-collapse-diffs="_collapseAllDiffs">
         </gr-file-list-header>
@@ -576,6 +578,7 @@
           change="[[_change]]"
           change-num="[[_changeNum]]"
           class$="[[_computeShowThreads(_showMessagesView)]]"
+          logged-in="[[_loggedIn]]"
           on-thread-list-modified="_handleReloadDiffComments"></gr-thread-list>
     </div>
     <gr-overlay id="downloadOverlay" with-backdrop>
@@ -586,6 +589,12 @@
           config="[[_serverConfig.download]]"
           on-close="_handleDownloadDialogClose"></gr-download-dialog>
     </gr-overlay>
+    <gr-overlay id="includedInOverlay" with-backdrop>
+      <gr-included-in-dialog
+          id="includedInDialog"
+          change-num="[[_changeNum]]"
+          on-close="_handleIncludedInDialogClose"></gr-included-in-dialog>
+    </gr-overlay>
     <gr-overlay id="replyOverlay"
         class="scrollable"
         no-cancel-on-outside-click
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
index a92af27..9be7db4 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
@@ -96,6 +99,7 @@
         type: Object,
         value() { return document.body; },
       },
+      _commentThreads: Array,
       /** @type {?} */
       _serverConfig: {
         type: Object,
@@ -525,6 +529,18 @@
       this.$.fileList.openDiffPrefs();
     },
 
+    _handleOpenIncludedInDialog() {
+      this.$.includedInDialog.loadData().then(() => {
+        Polymer.dom.flush();
+        this.$.includedInOverlay.refit();
+      });
+      this.$.includedInOverlay.open();
+    },
+
+    _handleIncludedInDialogClose(e) {
+      this.$.includedInOverlay.close();
+    },
+
     _handleOpenDownloadDialog() {
       this.$.downloadOverlay.open().then(() => {
         this.$.downloadOverlay
@@ -596,6 +612,13 @@
     },
 
     _paramsChanged(value) {
+      // Change the content of the comment tabs back to messages list, but
+      // do not yet change the tab itself. The animation of tab switching will
+      // get messed up if changed here, because it requires the tabs to be on
+      // the streen, and they are hidden shortly after this. The tab switching
+      // animation will happen in post render tasks.
+      this._showMessagesView = true;
+
       if (value.view !== Gerrit.Nav.View.CHANGE) {
         this._initialLoadComplete = false;
         return;
@@ -631,15 +654,6 @@
       this._changeNum = value.changeNum;
       this.$.relatedChanges.clear();
 
-      // If the comment tabs were already rendered, but set to the wrong initial
-      // value, swap them here so the thread tab doesn't flash before being
-      // swapped out. If the selected tab is undefined, we have to wait until
-      // the page is finished rendering to set selected to 0, otherwise the
-      // animation will not show.
-      if (this.$.commentTabs.selected === 1) {
-        this.$.commentTabs.selected = 0;
-      }
-
       this._reload().then(() => {
         this._performPostLoadTasks();
       });
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html
index 35c4bc1..4d33fab 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -406,10 +407,15 @@
         assert.notEqual(getComputedStyle(element.$.threadList).display,
             'none');
 
-        // When the change is partially reloaded (ex: Shift+R), paramsChanged
-        // will set the tab, if it was previously set to the thread tab.
+        // When the change is partially reloaded (ex: Shift+R), the content
+        // is swapped out before the tab, so messages list will display even
+        // though the tab for comment threads is still temporarily selected.
         element._paramsChanged(element.params);
-        assert.equal(element.$.commentTabs.selected, 0);
+        assert.equal(element.$.commentTabs.selected, 1);
+        assert.notEqual(getComputedStyle(element.$.messageList).display,
+            'none');
+        assert.equal(getComputedStyle(element.$.threadList).display,
+            'none');
         done();
       });
     });
diff --git a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.html b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.html
index 464e1bb..e0362c8 100644
--- a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.html
+++ b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.js b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.js
index b089ae5..cbc7e42 100644
--- a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.js
+++ b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
   Polymer({
diff --git a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list_test.html b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list_test.html
index 48bde1c..954507e 100644
--- a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.html b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.html
index 3eaeab25..96a5454 100644
--- a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.html
+++ b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.js b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.js
index dbf20f0..837de59 100644
--- a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.js
+++ b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info_test.html b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info_test.html
index 7704255..c0a09f3 100644
--- a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info_test.html
+++ b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.html b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.html
index a18e2a2..c086b9a 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.html
+++ b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.js
index a3500b0..03509ce 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog_test.html b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog_test.html
index b757c29..a5c047c 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.html b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.html
index 34688ad..1590fd9 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.html
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.js
index 03493fe..ea63dd5 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_test.html b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_test.html
index 33b9a88..5c51fe0 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.html b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.html
index 2e530d9..271dd3cc 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.html
+++ b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.js
index dee4a3a..f8d7151 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_test.html b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_test.html
index a873c29..e619425 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.html b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.html
index ea70de9..8e179cc 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.html
+++ b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.js
index e4f6e97..552bb61 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_test.html b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_test.html
index ccfc368..24815db 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.html b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.html
index 5b39547..8ccf15b 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.html
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.js
index 5b11652..1cae866 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_test.html b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_test.html
index c1220cb..c5a1bde 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.html b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.html
index fdd9b26..e9419e2 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.html
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js
index 41242f2..fa3e5c9 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html
index f6e1748..84fe8a9 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-constants.html b/polygerrit-ui/app/elements/change/gr-file-list-constants.html
index cfc129c..8bdcf7a 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-constants.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list-constants.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,4 +28,4 @@
 
     window.GrFileListConstants = GrFileListConstants;
   })(window);
-</script>
\ No newline at end of file
+</script>
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.html b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.html
index d02a189..122f1f9 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -80,6 +81,12 @@
       .downloadContainer {
         margin-right: 16px;
       }
+      .includedInContainer {
+        margin-right: 16px;
+      }
+      .includedInContainer.hide {
+        display: none;
+      }
       .rightControls {
         align-self: flex-end;
         margin: auto 0 auto auto;
@@ -209,6 +216,11 @@
               class="download"
               on-tap="_handleDownloadTap">Download</gr-button>
         </span>
+        <span class$="includedInContainer [[_hideIncludedIn(change)]] desktop">
+          <gr-button link
+              class="includedIn"
+              on-tap="_handleIncludedInTap">Included In</gr-button>
+        </span>
         <template is="dom-if"
             if="[[_fileListActionsVisible(shownFileCount, _maxFilesForBulkActions)]]">
           <gr-button
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.js b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.js
index 84add8a..7c5cbc9 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
@@ -149,7 +152,7 @@
           .then(res => {
             if (res.ok) {
               if (target) { target.disabled = false; }
-              this.set(['_change', 'revisions', sha, 'description'], desc);
+              this.set(['change', 'revisions', sha, 'description'], desc);
               this._patchsetDescription = desc;
             }
           }).catch(err => {
@@ -179,6 +182,11 @@
       this.fire('open-diff-prefs');
     },
 
+    _handleIncludedInTap(e) {
+      e.preventDefault();
+      this.fire('open-included-in-dialog');
+    },
+
     _handleDownloadTap(e) {
       e.preventDefault();
       this.fire('open-download-dialog');
@@ -199,5 +207,9 @@
     _getRevisionInfo(change) {
       return new Gerrit.RevisionInfo(change);
     },
+
+    _hideIncludedIn(change) {
+      return change && change.status === 'MERGED' ? '' : 'hide';
+    },
   });
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.html b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.html
index a92d783..ba186b2 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -134,6 +135,7 @@
         // The API stub should be called with an empty string for the new
         // description.
         assert.equal(putDescStub.lastCall.args[2], '');
+        assert.equal(element.change.revisions.rev1.description, '');
 
         flushAsynchronousOperations();
         // The editable label should now be visible and the chip hidden.
@@ -154,6 +156,7 @@
       }).then(() => {
         flushAsynchronousOperations();
         // The chip should be visible again, and the label hidden.
+        assert.equal(element.change.revisions.rev1.description, 'test2');
         assert.equal(getComputedStyle(label).display, 'none');
         assert.notEqual(getComputedStyle(chip).display, 'none');
       });
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 8154b9c..41818d1 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
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -88,7 +89,7 @@
         cursor: pointer;
       }
       .file-row.expanded {
-        background-color: #fff;
+        background-color: #eeeeee;
         border-bottom: 1px solid #ddd;
         position: -webkit-sticky;
         position: sticky;
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 640c273..91c9006 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
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
@@ -478,16 +481,18 @@
     },
 
     _handleShiftLeftKey(e) {
-      if (this.shouldSuppressKeyboardShortcut(e)) { return; }
-      if (!this._showInlineDiffs) { return; }
+      if (this.shouldSuppressKeyboardShortcut(e) || this._noDiffsExpanded()) {
+        return;
+      }
 
       e.preventDefault();
       this.$.diffCursor.moveLeft();
     },
 
     _handleShiftRightKey(e) {
-      if (this.shouldSuppressKeyboardShortcut(e)) { return; }
-      if (!this._showInlineDiffs) { return; }
+      if (this.shouldSuppressKeyboardShortcut(e) || this._noDiffsExpanded()) {
+        return;
+      }
 
       e.preventDefault();
       this.$.diffCursor.moveRight();
@@ -591,10 +596,10 @@
 
     _handleNKey(e) {
       if (this.shouldSuppressKeyboardShortcut(e) ||
-          this.modifierPressed(e) && !this.isModifierPressed(e, 'shiftKey')) {
+          (this.modifierPressed(e) && !this.isModifierPressed(e, 'shiftKey')) ||
+          this._noDiffsExpanded()) {
         return;
       }
-      if (!this._showInlineDiffs) { return; }
 
       e.preventDefault();
       if (this.isModifierPressed(e, 'shiftKey')) {
@@ -606,10 +611,10 @@
 
     _handlePKey(e) {
       if (this.shouldSuppressKeyboardShortcut(e) ||
-          this.modifierPressed(e) && !this.isModifierPressed(e, 'shiftKey')) {
+          (this.modifierPressed(e) && !this.isModifierPressed(e, 'shiftKey')) ||
+          this._noDiffsExpanded()) {
         return;
       }
-      if (!this._showInlineDiffs) { return; }
 
       e.preventDefault();
       if (this.isModifierPressed(e, 'shiftKey')) {
@@ -1129,5 +1134,13 @@
       }
       return `sizeBars desktop ${hideClass}`;
     },
+
+    /**
+     * Returns true if none of the inline diffs have been expanded.
+     * @return {boolean}
+     */
+    _noDiffsExpanded() {
+      return this.filesExpanded === GrFileListConstants.FilesExpandedState.NONE;
+    },
   });
 })();
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 36b5a41..e2a3bf4 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
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -597,6 +598,26 @@
           assert.deepEqual(interact(), {opened_selected: true});
         });
       });
+
+      test('shift+left/shift+right', () => {
+        const moveLeftStub = sandbox.stub(element.$.diffCursor, 'moveLeft');
+        const moveRightStub = sandbox.stub(element.$.diffCursor, 'moveRight');
+
+        let noDiffsExpanded = true;
+        sandbox.stub(element, '_noDiffsExpanded', () => noDiffsExpanded);
+
+        MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'left');
+        assert.isFalse(moveLeftStub.called);
+        MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'right');
+        assert.isFalse(moveRightStub.called);
+
+        noDiffsExpanded = false;
+
+        MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'left');
+        assert.isTrue(moveLeftStub.called);
+        MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'right');
+        assert.isTrue(moveRightStub.called);
+      });
     });
 
     test('computed properties', () => {
@@ -1367,6 +1388,7 @@
       let nextCommentStub;
       let nextChunkStub;
       let fileRows;
+
       setup(() => {
         sandbox.stub(element, '_renderInOrder').returns(Promise.resolve());
         nKeySpy = sandbox.spy(element, '_handleNKey');
@@ -1377,9 +1399,11 @@
         fileRows =
             Polymer.dom(element.root).querySelectorAll('.row:not(.header)');
       });
-      test('n key with all files expanded and no shift key', () => {
+
+      test('n key with some files expanded and no shift key', () => {
         MockInteractions.pressAndReleaseKeyOn(fileRows[0], 73, null, 'i');
         flushAsynchronousOperations();
+        assert.equal(nextChunkStub.callCount, 1);
 
         // Handle N key should return before calling diff cursor functions.
         MockInteractions.pressAndReleaseKeyOn(element, 78, null, 'n');
@@ -1387,21 +1411,22 @@
         assert.isFalse(nextCommentStub.called);
 
         // This is also called in diffCursor.moveToFirstChunk.
-        assert.equal(nextChunkStub.callCount, 1);
-        assert.isFalse(!!element._showInlineDiffs);
+        assert.equal(nextChunkStub.callCount, 2);
+        assert.equal(element.filesExpanded, 'some');
       });
 
-      test('n key with all files expanded and shift key', () => {
+      test('n key with some files expanded and shift key', () => {
         MockInteractions.pressAndReleaseKeyOn(fileRows[0], 73, null, 'i');
         flushAsynchronousOperations();
+        assert.equal(nextChunkStub.callCount, 1);
 
         MockInteractions.pressAndReleaseKeyOn(element, 78, 'shift', 'n');
         assert.isTrue(nKeySpy.called);
-        assert.isFalse(nextCommentStub.called);
+        assert.isTrue(nextCommentStub.called);
 
         // This is also called in diffCursor.moveToFirstChunk.
         assert.equal(nextChunkStub.callCount, 1);
-        assert.isFalse(!!element._showInlineDiffs);
+        assert.equal(element.filesExpanded, 'some');
       });
 
       test('n key without all files expanded and shift key', () => {
diff --git a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.html b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.html
new file mode 100644
index 0000000..ab77bf5
--- /dev/null
+++ b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.html
@@ -0,0 +1,101 @@
+<!--
+@license
+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.
+-->
+
+<link rel="import" href="../../../bower_components/polymer/polymer.html">
+<link rel="import" href="../../../styles/shared-styles.html">
+<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
+
+<dom-module id="gr-included-in-dialog">
+  <template>
+    <style include="shared-styles">
+      :host {
+        display: block;
+        max-height: 80vh;
+        overflow-y: auto;
+        padding: 4.5em 1em 1em 1em;
+      }
+      header {
+        background: #fff;
+        border-bottom: 1px solid #cdcdcd;
+        left: 0;
+        padding: 1em;
+        position: absolute;
+        right: 0;
+        top: 0;
+      }
+      #title {
+        display: inline-block;
+        font-size: 1.2rem;
+        margin-top: .2em;
+      }
+      h2 {
+        font-size: 1rem;
+      }
+      #filterInput {
+        display: inline-block;
+        float: right;
+        margin: 0 1em;
+        padding: .2em;
+      }
+      .closeButtonContainer {
+        float: right;
+      }
+      ul {
+        margin-bottom: 1em;
+      }
+      ul li {
+        border-radius: .2em;
+        background: #eee;
+        display: inline-block;
+        margin: 0 .2em .4em .2em;
+        padding: .2em .4em;
+      }
+      .loading.loaded {
+        display: none;
+      }
+    </style>
+    <header>
+      <h1 id="title">Included In:</h1>
+      <span class="closeButtonContainer">
+        <gr-button id="closeButton"
+            link
+            on-tap="_handleCloseTap">Close</gr-button>
+      </span>
+      <input
+          id="filterInput"
+          is="iron-input"
+          placeholder="Filter"
+          on-bind-value-changed="_onFilterChanged">
+    </header>
+    <div class$="[[_computeLoadingClass(_loaded)]]">Loading...</div>
+    <template
+        is="dom-repeat"
+        items="[[_computeGroups(_includedIn, _filterText)]]"
+        as="group">
+      <div>
+        <h2>[[group.title]]:</h2>
+        <ul>
+          <template is="dom-repeat" items="[[group.items]]">
+            <li>[[item]]</li>
+          </template>
+        </ul>
+      </div>
+    </template>
+    <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
+  </template>
+  <script src="gr-included-in-dialog.js"></script>
+</dom-module>
diff --git a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.js b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.js
new file mode 100644
index 0000000..d2ff035
--- /dev/null
+++ b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.js
@@ -0,0 +1,99 @@
+/**
+ * @license
+ * 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.
+ */
+(function() {
+  'use strict';
+
+  Polymer({
+    is: 'gr-included-in-dialog',
+
+    /**
+     * Fired when the user presses the close button.
+     *
+     * @event close
+     */
+
+    properties: {
+      /** @type {?} */
+      changeNum: {
+        type: Object,
+        observer: '_resetData',
+      },
+      /** @type {?} */
+      _includedIn: Object,
+      _loaded: {
+        type: Boolean,
+        value: false,
+      },
+      _filterText: {
+        type: String,
+        value: '',
+      },
+    },
+
+    loadData() {
+      if (!this.changeNum) { return; }
+      this._filterText = '';
+      return this.$.restAPI.getChangeIncludedIn(this.changeNum).then(
+          configs => {
+            if (!configs) { return; }
+            this._includedIn = configs;
+            this._loaded = true;
+          });
+    },
+
+    _resetData() {
+      this._includedIn = null;
+      this._loaded = false;
+    },
+
+    _computeGroups(includedIn, filterText) {
+      if (!includedIn) { return []; }
+
+      const filter = item => !filterText.length ||
+          item.toLowerCase().indexOf(filterText.toLowerCase()) !== -1;
+
+      const groups = [
+        {title: 'Branches', items: includedIn.branches.filter(filter)},
+        {title: 'Tags', items: includedIn.tags.filter(filter)},
+      ];
+      if (includedIn.external) {
+        for (const externalKey of Object.keys(includedIn.external)) {
+          groups.push({
+            title: externalKey,
+            items: includedIn.external[externalKey].filter(filter),
+          });
+        }
+      }
+      return groups.filter(g => g.items.length);
+    },
+
+    _handleCloseTap(e) {
+      e.preventDefault();
+      this.fire('close', null, {bubbles: false});
+    },
+
+    _computeLoadingClass(loaded) {
+      return loaded ? 'loading loaded' : 'loading';
+    },
+
+    _onFilterChanged() {
+      this.debounce('filter-change', () => {
+        this._filterText = this.$.filterInput.bindValue;
+      }, 100);
+    },
+  });
+})();
diff --git a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_test.html b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_test.html
new file mode 100644
index 0000000..539011a
--- /dev/null
+++ b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_test.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<!--
+@license
+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.
+-->
+
+<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+<title>gr-included-in-dialog</title>
+
+<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
+<script src="../../../bower_components/web-component-tester/browser.js"></script>
+<link rel="import" href="../../../test/common-test-setup.html"/>
+<link rel="import" href="gr-included-in-dialog.html">
+
+<script>void(0);</script>
+
+<test-fixture id="basic">
+  <template>
+    <gr-included-in-dialog></gr-included-in-dialog>
+  </template>
+</test-fixture>
+
+<script>
+  suite('gr-included-in-dialog', () => {
+    let element;
+    let sandbox;
+
+    setup(() => {
+      sandbox = sinon.sandbox.create();
+      element = fixture('basic');
+    });
+
+    teardown(() => { sandbox.restore(); });
+
+    test('_computeGroups', () => {
+      const includedIn = {branches: [], tags: []};
+      let filterText = '';
+      assert.deepEqual(element._computeGroups(includedIn, filterText), []);
+
+      includedIn.branches.push('master', 'development', 'stable-2.0');
+      includedIn.tags.push('v1.9', 'v2.0', 'v2.1');
+      assert.deepEqual(element._computeGroups(includedIn, filterText), [
+        {title: 'Branches', items: ['master', 'development', 'stable-2.0']},
+        {title: 'Tags', items: ['v1.9', 'v2.0', 'v2.1']},
+      ]);
+
+      includedIn.external = {};
+      assert.deepEqual(element._computeGroups(includedIn, filterText), [
+        {title: 'Branches', items: ['master', 'development', 'stable-2.0']},
+        {title: 'Tags', items: ['v1.9', 'v2.0', 'v2.1']},
+      ]);
+
+      includedIn.external.foo = ['abc', 'def', 'ghi'];
+      assert.deepEqual(element._computeGroups(includedIn, filterText), [
+        {title: 'Branches', items: ['master', 'development', 'stable-2.0']},
+        {title: 'Tags', items: ['v1.9', 'v2.0', 'v2.1']},
+        {title: 'foo', items: ['abc', 'def', 'ghi']},
+      ]);
+
+      filterText = 'v2';
+      assert.deepEqual(element._computeGroups(includedIn, filterText), [
+        {title: 'Tags', items: ['v2.0', 'v2.1']},
+      ]);
+
+      // Filtering is case-insensitive.
+      filterText = 'V2';
+      assert.deepEqual(element._computeGroups(includedIn, filterText), [
+        {title: 'Tags', items: ['v2.0', 'v2.1']},
+      ]);
+    });
+  });
+</script>
diff --git a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.html b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.html
index 819b6d9..54e8ae2 100644
--- a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.html
+++ b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.js b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.js
index 59f9f46..396fed8 100644
--- a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.js
+++ b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_test.html b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_test.html
index 49d0b67..e5431f6 100644
--- a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_test.html
+++ b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.html b/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.html
index 2532c77..7dd4c76 100644
--- a/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.html
+++ b/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.js b/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.js
index b3642a5..8734da2 100644
--- a/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.js
+++ b/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores_test.html b/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores_test.html
index e3a0d8c..24529ec 100644
--- a/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores_test.html
+++ b/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message.html b/polygerrit-ui/app/elements/change/gr-message/gr-message.html
index 0898a60..5a2ac1b 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message.html
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -123,6 +124,7 @@
       }
       .expanded .author {
         cursor: pointer;
+        margin-bottom: .4em;
       }
       .date {
         color: #666;
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message.js b/polygerrit-ui/app/elements/change/gr-message/gr-message.js
index fccde5b..a6d4b03 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message.js
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message_test.html b/polygerrit-ui/app/elements/change/gr-message/gr-message_test.html
index b0ba2d9..870f366 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message_test.html
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.html b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.html
index 2a173e5..df635bf 100644
--- a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.html
+++ b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.js b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.js
index 00097b0..89a3523 100644
--- a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.js
+++ b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_test.html b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_test.html
index 06801b8..80d1b9d 100644
--- a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.html b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.html
index ea98fb8..e78a228 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.html
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -181,4 +182,4 @@
     <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
   </template>
   <script src="gr-related-changes-list.js"></script>
-</dom-module>
\ No newline at end of file
+</dom-module>
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.js b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.js
index 6300cfb..c2ce364 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.js
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.html b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.html
index b639e3a..3f3a255 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog-it_test.html b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog-it_test.html
index 22b53c8..0cfae94 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog-it_test.html
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog-it_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.html b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.html
index bcaf973..088875f 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.html
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.js b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.js
index 4bd6db7..3875e25 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.html b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.html
index 7e0d5e7..b9eebdc 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/test/plugin.html b/polygerrit-ui/app/elements/change/gr-reply-dialog/test/plugin.html
index 70e1b83..3a8b2e1 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/test/plugin.html
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/test/plugin.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.html b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.html
index 54f2498..da5ab1e 100644
--- a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.html
+++ b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.js b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.js
index 348eabb..aa3ddea 100644
--- a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.js
+++ b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.html b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.html
index 24fc4d1..4e085d0 100644
--- a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.html b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.html
index c1f6820..4b36607 100644
--- a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.html
+++ b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2018 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -42,6 +43,12 @@
         min-height: 3.2em;
         padding: .5em var(--default-horizontal-margin);
       }
+      .toggleItem.draftToggle {
+        display: none;
+      }
+      .toggleItem.draftToggle.show {
+        display: flex;
+      }
       .toggleItem {
         align-items: center;
         display: flex;
@@ -63,7 +70,7 @@
             id="unresolvedToggle"
             on-change="_toggleUnresolved"></paper-toggle-button>
           Only unresolved threads</div>
-      <div class="toggleItem">
+      <div class$="toggleItem draftToggle [[_computeShowDraftToggle(loggedIn)]]">
         <paper-toggle-button
             id="draftToggle"
             on-change="_toggleDrafts"></paper-toggle-button>
diff --git a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.js b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.js
index 1ca667d..934f0f2 100644
--- a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.js
+++ b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.js
@@ -1,16 +1,19 @@
-// 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.
+/**
+ * @license
+ * 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.
+ */
 (function() {
   'use strict';
 
@@ -24,22 +27,28 @@
     is: 'gr-thread-list',
 
     properties: {
+      /** @type {?} */
       change: Object,
       threads: Array,
       changeNum: String,
+      loggedIn: Boolean,
       _sortedThreads: {
         type: Array,
         computed: '_computeSortedThreads(threads.*)',
       },
     },
 
+    _computeShowDraftToggle(loggedIn) {
+      return loggedIn ? 'show' : '';
+    },
+
     /**
      * Order as follows:
      *  - Unresolved threads with drafts (reverse chronological)
      *  - Unresolved threads without drafts (reverse chronological)
      *  - Resolved threads with drafts (reverse chronological)
      *  - Resolved threads without drafts (reverse chronological)
-     * @param {!Array} threads
+     * @param {!Object} changeRecord
      * @return {!Array}
      */
     _computeSortedThreads(changeRecord) {
diff --git a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_test.html b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_test.html
index c0be7d7..53557c6 100644
--- a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2018 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -186,6 +187,14 @@
       sandbox.restore();
     });
 
+    test('draft toggle only appears when logged in', () => {
+      assert.equal(getComputedStyle(element.$$('.draftToggle')).display,
+          'none');
+      element.loggedIn = true;
+      assert.notEqual(getComputedStyle(element.$$('.draftToggle')).display,
+          'none');
+    });
+
     test('there are five threads by default', () => {
       assert.equal(computeVisibleNumber(threadElements), 5);
     });
@@ -250,4 +259,4 @@
       assert.equal(dispatchSpy.lastCall.args[0].detail.path, '/COMMIT_MSG');
     });
   });
-</script>
\ No newline at end of file
+</script>
diff --git a/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.html b/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.html
index 0fb9df2..9a5fea8 100644
--- a/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.html
+++ b/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.js b/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.js
index 1bea61a..72ec7fa 100644
--- a/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.js
+++ b/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown_test.html b/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown_test.html
index 1183d9c..fe63a3e 100644
--- a/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown_test.html
+++ b/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.html b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.html
index 5765411..95c5403 100644
--- a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.html
+++ b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.js b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.js
index ac74ee5..758148e 100644
--- a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.js
+++ b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.html b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.html
index 17fa746..c4ba8d2 100644
--- a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.html
+++ b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.html b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.html
index 0d8bbbb..e2ef7c1 100644
--- a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.html
+++ b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.js b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.js
index b7900c0..e5dd019 100644
--- a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.js
+++ b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html
index 1728d46..4823ef93 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.js b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.js
index fe4f7cf..3ef6126 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.js
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.html b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.html
index 5da8382..1fd0402 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.html
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
index 4647e52..b97c056 100644
--- a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
+++ b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -417,6 +418,14 @@
       },
 
       /**
+       * Navigate to a repo settings page.
+       * @param {string} repoName
+       */
+      navigateToRepo(repoName) {
+        this._navigate(this.getUrlForRepo(repoName));
+      },
+
+      /**
        * @param {string} repoName
        * @return {string}
        */
diff --git a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation_test.html b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation_test.html
index b829e83..61d1100 100644
--- a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation_test.html
+++ b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.html b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.html
index d5d33ab..3181a0b 100644
--- a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.html
+++ b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.js b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.js
index 5a8ddf6..49edbd5 100644
--- a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.js
+++ b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting_test.html b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting_test.html
index e88096b..c3208ab 100644
--- a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting_test.html
+++ b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router.html b/polygerrit-ui/app/elements/core/gr-router/gr-router.html
index 2ef65f4..0d05bf1 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router.html
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router.js b/polygerrit-ui/app/elements/core/gr-router/gr-router.js
index 322d406..4ee00fb 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router.js
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html b/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html
index d0beb91..3572e89 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.html b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.html
index 94e3e4a19..169fd85 100644
--- a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.html
+++ b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.js b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.js
index a6f27489..c410486 100644
--- a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.js
+++ b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar_test.html b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar_test.html
index 9551c79..60e8a7e 100644
--- a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar_test.html
+++ b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api-mock.js b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api-mock.js
index 3e554c6..b7994e6 100644
--- a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api-mock.js
+++ b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api-mock.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.html b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.html
index 68e2ff8..c31bd1166 100644
--- a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.html
+++ b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.js b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.js
index 68d0801..065219a 100644
--- a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.js
+++ b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
@@ -207,6 +210,7 @@
    *
    * @param {!string} path
    * @param {number=} opt_patchNum
+   * @param {boolean=} opt_includeDrafts
    * @return {!Array}
    */
   ChangeComments.prototype.getAllCommentsForPath = function(path,
diff --git a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_test.html b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_test.html
index 2b06a10..1e53a14 100644
--- a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.html b/polygerrit-ui/app/elements/diff/gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.html
index 8cefabb..1a6245d 100644
--- a/polygerrit-ui/app/elements/diff/gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.html
+++ b/polygerrit-ui/app/elements/diff/gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.js b/polygerrit-ui/app/elements/diff/gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.js
index e0eb078..b86b72a 100644
--- a/polygerrit-ui/app/elements/diff/gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.js
+++ b/polygerrit-ui/app/elements/diff/gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-binary.js b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-binary.js
index 4f67142..02ad67b 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-binary.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-binary.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function(window, GrDiffBuilderSideBySide) {
   'use strict';
 
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 971d012..9f07d90 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
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the 'License');
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an 'AS IS' BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function(window, GrDiffBuilderSideBySide) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-side-by-side.js b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-side-by-side.js
index 06989d2..3d6dedd 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-side-by-side.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-side-by-side.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the 'License');
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an 'AS IS' BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function(window, GrDiffBuilder) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified.js b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified.js
index a033c7b..65a31a1 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the 'License');
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an 'AS IS' BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function(window, GrDiffBuilder) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html
index 708eb53..9aec1e8 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.js b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.js
index 522ee52..017f2a3 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the 'License');
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an 'AS IS' BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function(window, GrDiffGroup, GrDiffLine) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html
index 9f3bf0f..78efae7 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.html b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.html
index 5ca8a31..bdc412e 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.js b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.js
index 42a2c80..b053330 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group_test.html b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group_test.html
index 309611d..b0ee743 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.html b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.html
index 34e006f..6f597d7 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.js b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.js
index 8f5821f..136d23f 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread_test.html b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread_test.html
index 5eb8b94..6fb27ec 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.html b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.html
index e1ebbf2..b6409792 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -52,9 +53,6 @@
       :host([disabled]) .date {
         opacity: .5;
       }
-      :host([is-robot-comment]) {
-        background-color: #cfe8fc;
-      }
       .header {
         align-items: baseline;
         cursor: pointer;
@@ -101,6 +99,16 @@
         margin-left: 1em;
         --gr-button-color: #212121;
       }
+      .robotActions {
+        display: flex;
+        justify-content: flex-start;
+        padding-top: 0;
+      }
+      .robotActions .action {
+        /* Keep button text lined up with output text */
+        margin-left: -.3rem;
+        margin-right: 1em;
+      }
       .rightActions {
         display: flex;
         justify-content: flex-end;
@@ -149,7 +157,7 @@
         margin-top: -.4em;
       }
       .runIdInformation {
-        margin: 1em 0;
+        margin: .7em 0;
       }
       .robotRun {
         margin-left: .5em;
@@ -273,17 +281,24 @@
             disabled="{{disabled}}"
             rows="4"
             text="{{_messageText}}"></gr-textarea>
+        <!--The message class is needed to ensure selectability from
+        gr-diff-selection.-->
         <gr-formatted-text class="message"
             content="[[comment.message]]"
             no-trailing-margin="[[!comment.__draft]]"
             collapsed="[[collapsed]]"
             config="[[projectConfig.commentlinks]]"></gr-formatted-text>
-        <div hidden$="[[!comment.robot_run_id]]">
+        <div hidden$="[[!comment.robot_run_id]]" class="message">
           <div class="runIdInformation" hidden$="[[collapsed]]">
             Run ID:
-            <a class="robotRunLink" href$="[[comment.url]]">
-              <span class="robotRun">[[comment.robot_run_id]]</span>
-            </a>
+            <template is="dom-if" if="[[comment.url]]">
+              <a class="robotRunLink" href$="[[comment.url]]">
+                <span class="robotRun link">[[comment.robot_run_id]]</span>
+              </a>
+            </template>
+            <template is="dom-if" if="[[!comment.url]]">
+              <span class="robotRun text">[[comment.robot_run_id]]</span>
+            </template>
           </div>
         </div>
         <div class="actions humanActions" hidden$="[[!_showHumanActions]]">
@@ -309,17 +324,17 @@
             </gr-button>
           </div>
         </div>
-        <div class="actions robotActions" hidden$="[[!_showRobotActions]]">
+        <div class="robotActions" hidden$="[[!_showRobotActions]]">
           <template is="dom-if" if="[[isRobotComment]]">
-            <gr-endpoint-decorator name="robot-comment-controls">
-              <gr-endpoint-param name="comment" value="[[comment]]">
-              </gr-endpoint-param>
-            </gr-endpoint-decorator>
             <gr-button link class="action fix"
                 on-tap="_handleFix"
                 disabled="[[robotButtonDisabled]]">
               Please Fix
             </gr-button>
+            <gr-endpoint-decorator name="robot-comment-controls">
+              <gr-endpoint-param name="comment" value="[[comment]]">
+              </gr-endpoint-param>
+            </gr-endpoint-decorator>
           </template>
         </div>
       </div>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js
index c48f7ea..9e5ae87 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html
index 8c78946..d124764 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -385,6 +386,23 @@
       element.draft = false;
       assert.isTrue(element.$$('.humanActions').hasAttribute('hidden'));
       assert.isFalse(element.$$('.robotActions').hasAttribute('hidden'));
+
+      // A robot comment with run ID should display plain text.
+      element.set(['comment', 'robot_run_id'], 'text');
+      element.editing = false;
+      element.collapsed = false;
+      flushAsynchronousOperations();
+      assert.isNotOk(element.$$('.robotRun.link'));
+      assert.notEqual(getComputedStyle(element.$$('.robotRun.text')).display,
+          'none');
+
+      // A robot comment with run ID and url should display a link.
+      element.set(['comment', 'url'], '/path/to/run');
+      flushAsynchronousOperations();
+      assert.notEqual(getComputedStyle(element.$$('.robotRun.link')).display,
+          'none');
+      assert.equal(getComputedStyle(element.$$('.robotRun.text')).display,
+          'none');
     });
 
     test('collapsible drafts', () => {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.html b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.html
index 564312f..c24574e 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.js b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.js
index 92311b1..aee7a62 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.html b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.html
index ab3302b..8a89937 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-annotation.js b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-annotation.js
index e18f6ca..c1d53aa 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-annotation.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-annotation.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the 'License');
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an 'AS IS' BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function(window) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-annotation_test.html b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-annotation_test.html
index b237685..652aa4c 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-annotation_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-annotation_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.html b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.html
index c60f843..ae62b2e 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.js b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.js
index 03380e4..a45f8ec 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.html b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.html
index 4bbf12b..a82a11e 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-range-normalizer.js b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-range-normalizer.js
index 1ea5037..eb4123d 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-range-normalizer.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-range-normalizer.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the 'License');
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an 'AS IS' BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function(window) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.html b/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.html
index 4c4e314..be257d4 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2018 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.js b/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.js
index 6c3a713..88dd91a 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.js
@@ -1,16 +1,19 @@
-// 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.
+/**
+ * @license
+ * 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector_test.html b/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector_test.html
index c791091..c011106 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2018 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.html b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.html
index 9b830cf..d4bcef4 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -101,8 +102,7 @@
               id="lineWrappingInput"
               on-tap="_handlelineWrappingTap">
         </div>
-        <div class="pref" id="columnsPref"
-            hidden$="[[_newPrefs.line_wrapping]]">
+        <div class="pref" id="columnsPref">
           <label for="columnsInput">Diff width</label>
           <input is="iron-input" type="number" id="columnsInput"
               prevent-invalid-input
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.js b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.js
index ccc5361..47a3c2d 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences_test.html b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences_test.html
index f06cd3a..d9e14c0 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -77,18 +78,6 @@
       assert.isFalse(element._newPrefs.syntax_highlighting);
     });
 
-    test('clicking fit to screen hides line length input', () => {
-      element.prefs = {line_wrapping: false};
-
-      assert.isFalse(element.$.columnsPref.hidden);
-
-      MockInteractions.tap(element.$.lineWrappingInput);
-      assert.isTrue(element.$.columnsPref.hidden);
-
-      MockInteractions.tap(element.$.lineWrappingInput);
-      assert.isFalse(element.$.columnsPref.hidden);
-    });
-
     test('clicking save button calls _handleSave function', () => {
       const savePrefs = sinon.stub(element, '_handleSave');
       MockInteractions.tap(element.$.saveButton);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.html b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.html
index cae8bad..baa8bba 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.js b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.js
index 230cea9..dead8d7 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor_test.html b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor_test.html
index fcb8aec..7ccd9f8 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.html b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.html
index 2e56918..f9822f2 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.js b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.js
index 850785b..35e2fe1 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection_test.html b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection_test.html
index 79b66c1..f34429b8 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
index 3bf8df7..c7a1d86 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,6 +26,7 @@
 <link rel="import" href="../../shared/gr-button/gr-button.html">
 <link rel="import" href="../../shared/gr-count-string-formatter/gr-count-string-formatter.html">
 <link rel="import" href="../../shared/gr-dropdown-list/gr-dropdown-list.html">
+<link rel="import" href="../../shared/gr-fixed-panel/gr-fixed-panel.html">
 <link rel="import" href="../../shared/gr-icons/gr-icons.html">
 <link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
 <link rel="import" href="../../shared/gr-select/gr-select.html">
@@ -54,6 +56,11 @@
           border-bottom: 1px solid #eee;
         }
       }
+      gr-fixed-panel {
+        background-color: #fff;
+        border-bottom: 1px #eee solid;
+        z-index: 1;
+      }
       header,
       .subHeader {
         align-items: center;
@@ -141,15 +148,6 @@
       .separator.hide {
         display: none;
       }
-      .sticky {
-        background: #fff;
-        border-bottom: 1px solid #eee;
-        left: 0;
-        position: sticky;
-        top: 0;
-        width: 100vw;
-        z-index: 1;
-      }
       gr-dropdown-list {
         --trigger-style: {
           text-transform: none;
@@ -208,136 +206,138 @@
         }
       }
     </style>
-    <div>
-      <div class="sticky">
-        <header class$="[[_computeContainerClass(_editMode)]]">
-          <h3>
-            <a href$="[[_computeChangePath(_change, _patchRange.*, _change.revisions)]]">
-              [[_changeNum]]</a><span>:</span>
-            <span>[[_change.subject]]</span>
-            <span class="dash">—</span>
-            <input id="reviewed"
-                class="reviewed hideOnEdit"
-                type="checkbox"
-                on-change="_handleReviewedChange"
-                hidden$="[[!_loggedIn]]" hidden>
-            <div class="jumpToFileContainer">
-              <gr-dropdown-list
-                  id="dropdown"
-                  value="[[_path]]"
-                  on-value-change="_handleFileChange"
-                  items="[[_formattedFiles]]"
-                  initial-count="75">
-            </gr-dropdown-list>
-            </div>
-          </h3>
-          <div class="navLinks desktop">
-            <span class$="fileNum [[_computeFileNumClass(_fileNum, _formattedFiles)]]">
-              File [[_fileNum]] of [[_formattedFiles.length]]
-              <span class="separator"></span>
-            </span>
-            <a class="navLink"
-                href$="[[_computeNavLinkURL(_change, _path, _fileList, -1, 1)]]">
-              Prev</a>
-            <span class="separator"></span>
-            <a class="navLink"
-                href$="[[_computeChangePath(_change, _patchRange.*, _change.revisions)]]">
-              Up</a>
-            <span class="separator"></span>
-            <a class="navLink"
-                href$="[[_computeNavLinkURL(_change, _path, _fileList, 1, 1)]]">
-              Next</a>
+    <gr-fixed-panel
+        class$="[[_computeContainerClass(_editMode)]]"
+        floating-disabled="[[_panelFloatingDisabled]]"
+        keep-on-scroll
+        ready-for-measure="[[!_loading]]">
+      <header>
+        <h3>
+          <a href$="[[_computeChangePath(_change, _patchRange.*, _change.revisions)]]">
+            [[_changeNum]]</a><span>:</span>
+          <span>[[_change.subject]]</span>
+          <span class="dash">—</span>
+          <input id="reviewed"
+              class="reviewed hideOnEdit"
+              type="checkbox"
+              on-change="_handleReviewedChange"
+              hidden$="[[!_loggedIn]]" hidden>
+          <div class="jumpToFileContainer">
+            <gr-dropdown-list
+                id="dropdown"
+                value="[[_path]]"
+                on-value-change="_handleFileChange"
+                items="[[_formattedFiles]]"
+                initial-count="75">
+           </gr-dropdown-list>
           </div>
-        </header>
-        <div class="subHeader">
-          <div class="patchRangeLeft">
-            <gr-patch-range-select
-                id="rangeSelect"
-                change-num="[[_changeNum]]"
-                change-comments="[[_changeComments]]"
-                patch-num="[[_patchRange.patchNum]]"
-                base-patch-num="[[_patchRange.basePatchNum]]"
-                files-weblinks="[[_filesWeblinks]]"
-                available-patches="[[_allPatchSets]]"
-                revisions="[[_change.revisions]]"
-                revision-info="[[_revisionInfo]]"
-                on-patch-range-change="_handlePatchChange">
-            </gr-patch-range-select>
-            <span class="download desktop">
-              <span class="separator"></span>
-              <a
-                class="downloadLink"
-                download
-                href$="[[_computeDownloadLink(_changeNum, _patchRange, _path)]]">
-                Download
-              </a>
-            </span>
+        </h3>
+        <div class="navLinks desktop">
+          <span class$="fileNum [[_computeFileNumClass(_fileNum, _formattedFiles)]]">
+            File [[_fileNum]] of [[_formattedFiles.length]]
+            <span class="separator"></span>
+          </span>
+          <a class="navLink"
+              href$="[[_computeNavLinkURL(_change, _path, _fileList, -1, 1)]]">
+            Prev</a>
+          <span class="separator"></span>
+          <a class="navLink"
+              href$="[[_computeChangePath(_change, _patchRange.*, _change.revisions)]]">
+            Up</a>
+          <span class="separator"></span>
+          <a class="navLink"
+              href$="[[_computeNavLinkURL(_change, _path, _fileList, 1, 1)]]">
+            Next</a>
+        </div>
+      </header>
+      <div class="subHeader">
+        <div class="patchRangeLeft">
+          <gr-patch-range-select
+              id="rangeSelect"
+              change-num="[[_changeNum]]"
+              change-comments="[[_changeComments]]"
+              patch-num="[[_patchRange.patchNum]]"
+              base-patch-num="[[_patchRange.basePatchNum]]"
+              files-weblinks="[[_filesWeblinks]]"
+              available-patches="[[_allPatchSets]]"
+              revisions="[[_change.revisions]]"
+              revision-info="[[_revisionInfo]]"
+              on-patch-range-change="_handlePatchChange">
+          </gr-patch-range-select>
+          <span class="download desktop">
+            <span class="separator"></span>
+            <a
+              class="downloadLink"
+              download
+              href$="[[_computeDownloadLink(_changeNum, _patchRange, _path)]]">
+              Download
+            </a>
+          </span>
+        </div>
+        <div class="rightControls">
+          <span class$="blameLoader [[_computeBlameLoaderClass(_isImageDiff, _isBlameSupported)]]">
+            <gr-button
+                link
+                disabled="[[_isBlameLoading]]"
+                on-tap="_toggleBlame">[[_computeBlameToggleLabel(_isBlameLoaded, _isBlameLoading)]]</gr-button>
+            <span class="separator"></span>
+          </span>
+          <div class$="diffModeSelector [[_computeModeSelectHideClass(_isImageDiff)]]">
+            <span>Diff view:</span>
+            <gr-diff-mode-selector
+                id="modeSelect"
+                save-on-change="[[_loggedIn]]"
+                mode="{{changeViewState.diffMode}}"></gr-diff-mode-selector>
           </div>
-          <div class="rightControls">
-            <span class$="blameLoader [[_computeBlameLoaderClass(_isImageDiff, _isBlameSupported)]]">
+          <span id="diffPrefsContainer"
+              hidden$="[[_computePrefsButtonHidden(_prefs, _loggedIn)]]" hidden>
+            <span class="preferences desktop">
               <gr-button
                   link
-                  disabled="[[_isBlameLoading]]"
-                  on-tap="_toggleBlame">[[_computeBlameToggleLabel(_isBlameLoaded, _isBlameLoading)]]</gr-button>
-              <span class="separator"></span>
+                  class="prefsButton"
+                  has-tooltip
+                  title="Diff preferences"
+                  on-tap="_handlePrefsTap"><iron-icon icon="gr-icons:settings"></iron-icon></gr-button>
             </span>
-            <div class$="diffModeSelector [[_computeModeSelectHideClass(_isImageDiff)]]">
-              <span>Diff view:</span>
-              <gr-diff-mode-selector
-                  id="modeSelect"
-                  save-on-change="[[_loggedIn]]"
-                  mode="{{changeViewState.diffMode}}"></gr-diff-mode-selector>
-            </div>
-            <span id="diffPrefsContainer"
-                hidden$="[[_computePrefsButtonHidden(_prefs, _loggedIn)]]" hidden>
-              <span class="preferences desktop">
-                <gr-button
-                    link
-                    class="prefsButton"
-                    has-tooltip
-                    title="Diff preferences"
-                    on-tap="_handlePrefsTap"><iron-icon icon="gr-icons:settings"></iron-icon></gr-button>
-              </span>
+          </span>
+          <gr-endpoint-decorator name="annotation-toggler">
+            <span hidden id="annotation-span">
+              <label for="annotation-checkbox" id="annotation-label"></label>
+              <input is="iron-input" type="checkbox" id="annotation-checkbox" disabled>
             </span>
-            <gr-endpoint-decorator name="annotation-toggler">
-              <span hidden id="annotation-span">
-                <label for="annotation-checkbox" id="annotation-label"></label>
-                <input is="iron-input" type="checkbox" id="annotation-checkbox" disabled>
-              </span>
-            </gr-endpoint-decorator>
-          </div>
-        </div>
-        <div class="fileNav mobile">
-          <a class="mobileNavLink"
-            href$="[[_computeNavLinkURL(_change, _path, _fileList, -1, 1)]]">
-            &lt;</a>
-          <div class="fullFileName mobile">[[computeDisplayPath(_path)]]
-          </div>
-          <a class="mobileNavLink"
-              href$="[[_computeNavLinkURL(_change, _path, _fileList, 1, 1)]]">
-            &gt;</a>
+          </gr-endpoint-decorator>
         </div>
       </div>
-      <div class="loading" hidden$="[[!_loading]]">Loading...</div>
-      <gr-diff
-          id="diff"
-          hidden
-          hidden$="[[_loading]]"
-          class$="[[_computeDiffClass(_panelFloatingDisabled)]]"
-          is-image-diff="{{_isImageDiff}}"
-          files-weblinks="{{_filesWeblinks}}"
-          change-num="[[_changeNum]]"
-          commit-range="[[_commitRange]]"
-          patch-range="[[_patchRange]]"
-          path="[[_path]]"
-          prefs="[[_prefs]]"
-          project-config="[[_projectConfig]]"
-          project-name="[[_change.project]]"
-          view-mode="[[_diffMode]]"
-          is-blame-loaded="{{_isBlameLoaded}}"
-          on-line-selected="_onLineSelected">
-      </gr-diff>
-    </div>
+      <div class="fileNav mobile">
+        <a class="mobileNavLink"
+          href$="[[_computeNavLinkURL(_change, _path, _fileList, -1, 1)]]">
+          &lt;</a>
+        <div class="fullFileName mobile">[[computeDisplayPath(_path)]]
+        </div>
+        <a class="mobileNavLink"
+            href$="[[_computeNavLinkURL(_change, _path, _fileList, 1, 1)]]">
+          &gt;</a>
+      </div>
+    </gr-fixed-panel>
+    <div class="loading" hidden$="[[!_loading]]">Loading...</div>
+    <gr-diff
+        id="diff"
+        hidden
+        hidden$="[[_loading]]"
+        class$="[[_computeDiffClass(_panelFloatingDisabled)]]"
+        is-image-diff="{{_isImageDiff}}"
+        files-weblinks="{{_filesWeblinks}}"
+        change-num="[[_changeNum]]"
+        commit-range="[[_commitRange]]"
+        patch-range="[[_patchRange]]"
+        path="[[_path]]"
+        prefs="[[_prefs]]"
+        project-config="[[_projectConfig]]"
+        project-name="[[_change.project]]"
+        view-mode="[[_diffMode]]"
+        is-blame-loaded="{{_isBlameLoaded}}"
+        on-line-selected="_onLineSelected">
+    </gr-diff>
     <gr-diff-preferences
         id="diffPreferences"
         prefs="{{_prefs}}"
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
index b1b0670..e37970a 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html
index 0e9c34b..c85ea28 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-group.js b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-group.js
index 8d1cef6..88fcd0e 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-group.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-group.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the 'License');
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an 'AS IS' BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function(window, GrDiffLine) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-group_test.html b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-group_test.html
index 32405cf..9dc5311 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-group_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-group_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-line.js b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-line.js
index 8db0c4f..978058f 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-line.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-line.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function(window) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
index 079600c..99cfb03 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -48,7 +49,6 @@
         display: none;
       }
       .diffContainer {
-        border-bottom: 1px solid #eee;
         display: flex;
         font: var(--font-size-small) var(--monospace-font-family);
         @apply --diff-container-styles;
@@ -240,6 +240,19 @@
         overflow: hidden;
         width: 200px;
       }
+      /** Since the line limit position is determined by charachter size, blank
+       lines also need to have the same font size as everything else */
+      .full-width .blank {
+        font-size: var(--font-size, var(--font-size-small));
+      }
+      /** Support the line length indicator **/
+      .full-width td.content,
+      .full-width td.blank {
+        /* Base 64 encoded 1x1px of #ddd */
+        background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mO8+x8AAr8B3gzOjaQAAAAASUVORK5CYII=');
+        background-position: var(--line-limit) 0;
+        background-repeat: repeat-y;
+      }
     </style>
     <style include="gr-theme-default"></style>
     <div id="diffHeader" hidden$="[[_computeDiffHeaderHidden(_diffHeaderItems)]]">
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
index 19b3c6d..9841564 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
@@ -20,6 +23,10 @@
   const ERR_INVALID_LINE = 'Invalid line number: ';
   const MSG_EMPTY_BLAME = 'No blame information for this diff.';
 
+  const EVENT_AGAINST_PARENT = 'diff-against-parent';
+  const EVENT_ZERO_REBASE = 'rebase-percent-zero';
+  const EVENT_NONZERO_REBASE = 'rebase-percent-nonzero';
+
   const DiffViewMode = {
     SIDE_BY_SIDE: 'SIDE_BY_SIDE',
     UNIFIED: 'UNIFIED_DIFF',
@@ -623,6 +630,7 @@
         this._diffTableClass = 'full-width';
         if (this.viewMode === 'SIDE_BY_SIDE') {
           stylesToUpdate['--content-width'] = 'none';
+          stylesToUpdate['--line-limit'] = prefs.line_length + 'ch';
         }
       } else {
         this._diffTableClass = '';
@@ -728,9 +736,16 @@
       const percentRebaseDelta = !totalDelta ? 0 :
           Math.round(100 * rebaseDelta / totalDelta);
 
-      // Report the percentage in the "diff" category.
-      this.$.reporting.reportInteraction('rebase-delta-percent',
-          percentRebaseDelta);
+      // Report the due_to_rebase percentage in the "diff" category when
+      // applicable.
+      if (this.patchRange.basePatchNum === 'PARENT') {
+        this.$.reporting.reportInteraction(EVENT_AGAINST_PARENT);
+      } else if (percentRebaseDelta === 0) {
+        this.$.reporting.reportInteraction(EVENT_ZERO_REBASE);
+      } else {
+        this.$.reporting.reportInteraction(EVENT_NONZERO_REBASE,
+            percentRebaseDelta);
+      }
     },
 
     /** @return {!Promise} */
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
index 7526141..33abab4 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -70,6 +71,20 @@
       assert.equal(element._diffLength(mock.diffResponse), 52);
     });
 
+    test('line limit with line_wrapping', () => {
+      element = fixture('basic');
+      element.prefs = {line_wrapping: true, line_length: 80, tab_size: 2};
+      flushAsynchronousOperations();
+      assert.equal(element.customStyle['--line-limit'], '80ch');
+    });
+
+    test('line limit without line_wrapping', () => {
+      element = fixture('basic');
+      element.prefs = {line_wrapping: false, line_length: 80, tab_size: 2};
+      flushAsynchronousOperations();
+      assert.isNotOk(element.customStyle['--line-limit']);
+    });
+
     suite('_get{PatchNum|IsParentComment}ByLineAndContent', () => {
       let lineEl;
       let contentEl;
@@ -1165,6 +1180,7 @@
 
       setup(() => {
         element = fixture('basic');
+        element.patchRange = {basePatchNum: 1};
         reportStub = sandbox.stub(element.$.reporting, 'reportInteraction');
       });
 
@@ -1185,7 +1201,8 @@
         };
         element._reportDiff(diff);
         assert.isTrue(reportStub.calledOnce);
-        assert.strictEqual(reportStub.lastCall.args[1], 0);
+        assert.equal(reportStub.lastCall.args[0], 'rebase-percent-zero');
+        assert.isUndefined(reportStub.lastCall.args[1]);
       });
 
       test('diff w/ no rebase delta', () => {
@@ -1202,7 +1219,8 @@
         };
         element._reportDiff(diff);
         assert.isTrue(reportStub.calledOnce);
-        assert.strictEqual(reportStub.lastCall.args[1], 0);
+        assert.equal(reportStub.lastCall.args[0], 'rebase-percent-zero');
+        assert.isUndefined(reportStub.lastCall.args[1]);
       });
 
       test('diff w/ some rebase delta', () => {
@@ -1220,6 +1238,7 @@
         };
         element._reportDiff(diff);
         assert.isTrue(reportStub.calledOnce);
+        assert.equal(reportStub.lastCall.args[0], 'rebase-percent-nonzero');
         assert.strictEqual(reportStub.lastCall.args[1], 50);
       });
 
@@ -1231,8 +1250,21 @@
         }]};
         element._reportDiff(diff);
         assert.isTrue(reportStub.calledOnce);
+        assert.equal(reportStub.lastCall.args[0], 'rebase-percent-nonzero');
         assert.strictEqual(reportStub.lastCall.args[1], 100);
       });
+
+      test('diff against parent event', () => {
+        element.patchRange.basePatchNum = 'PARENT';
+        const diff = {content: [{
+          a: ['foo', 'bar'],
+          b: ['baz', 'foo'],
+        }]};
+        element._reportDiff(diff);
+        assert.isTrue(reportStub.calledOnce);
+        assert.equal(reportStub.lastCall.args[0], 'diff-against-parent');
+        assert.isUndefined(reportStub.lastCall.args[1]);
+      });
     });
   });
 
diff --git a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.html b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.html
index 7fd97ad..cfc76b7 100644
--- a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.html
+++ b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.js b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.js
index 40259c6..cf8118f 100644
--- a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.js
+++ b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.html b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.html
index 2ae928d..2614885 100644
--- a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.html b/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.html
index ba6973b..71b5bc3 100644
--- a/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.html
+++ b/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.js b/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.js
index 3de18be..6c7903d 100644
--- a/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.js
+++ b/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer_test.html b/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer_test.html
index afdf630..c541e26 100644
--- a/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-ranged-comment-layer/gr-ranged-comment-layer_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box.html b/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box.html
index 5f96fce..3209d63 100644
--- a/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box.html
+++ b/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box.js b/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box.js
index 61a6eb2..6349ab6 100644
--- a/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box.js
+++ b/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box_test.html b/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box_test.html
index 7fc634c..19155e4 100644
--- a/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-selection-action-box/gr-selection-action-box_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer.html b/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer.html
index 9c5d6bf..cd9f9dc 100644
--- a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer.html
+++ b/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer.js b/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer.js
index 6eac3a5..92c2eb9 100644
--- a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer.js
+++ b/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_test.html b/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_test.html
index 98a6f8e..74fc3bf 100644
--- a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-syntax-lib-loader/gr-syntax-lib-loader.html b/polygerrit-ui/app/elements/diff/gr-syntax-lib-loader/gr-syntax-lib-loader.html
index fedd22a..f5b71be 100644
--- a/polygerrit-ui/app/elements/diff/gr-syntax-lib-loader/gr-syntax-lib-loader.html
+++ b/polygerrit-ui/app/elements/diff/gr-syntax-lib-loader/gr-syntax-lib-loader.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-syntax-lib-loader/gr-syntax-lib-loader.js b/polygerrit-ui/app/elements/diff/gr-syntax-lib-loader/gr-syntax-lib-loader.js
index ca3cf62..6ec7ab2 100644
--- a/polygerrit-ui/app/elements/diff/gr-syntax-lib-loader/gr-syntax-lib-loader.js
+++ b/polygerrit-ui/app/elements/diff/gr-syntax-lib-loader/gr-syntax-lib-loader.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/diff/gr-syntax-lib-loader/gr-syntax-lib-loader_test.html b/polygerrit-ui/app/elements/diff/gr-syntax-lib-loader/gr-syntax-lib-loader_test.html
index 6e88ed1..a260a97 100644
--- a/polygerrit-ui/app/elements/diff/gr-syntax-lib-loader/gr-syntax-lib-loader_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-syntax-lib-loader/gr-syntax-lib-loader_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/diff/gr-syntax-themes/gr-theme-default.html b/polygerrit-ui/app/elements/diff/gr-syntax-themes/gr-theme-default.html
index d160cb3..b6a84ad 100644
--- a/polygerrit-ui/app/elements/diff/gr-syntax-themes/gr-theme-default.html
+++ b/polygerrit-ui/app/elements/diff/gr-syntax-themes/gr-theme-default.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -83,4 +84,4 @@
       }
     </style>
   </template>
-</dom-module>
\ No newline at end of file
+</dom-module>
diff --git a/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.html b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.html
index 5290bba..093e979 100644
--- a/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.html
+++ b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -39,4 +40,4 @@
         on-input="_handleTextareaInput"></textarea>
   </template>
   <script src="gr-default-editor.js"></script>
-</dom-module>
\ No newline at end of file
+</dom-module>
diff --git a/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.js b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.js
index f30f9fa..168ded8 100644
--- a/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.js
+++ b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
@@ -32,4 +35,4 @@
           {detail: {value: e.target.value}, bubbles: true}));
     },
   });
-})();
\ No newline at end of file
+})();
diff --git a/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor_test.html b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor_test.html
index 43ec9e5..b79cd9d 100644
--- a/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor_test.html
+++ b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor_test.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -52,4 +53,4 @@
           {target: textarea, bubbles: true}));
     });
   });
-</script>
\ No newline at end of file
+</script>
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-constants.html b/polygerrit-ui/app/elements/edit/gr-edit-constants.html
index 4bae900..d526ccd 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-constants.html
+++ b/polygerrit-ui/app/elements/edit/gr-edit-constants.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -29,4 +30,4 @@
 
     window.GrEditConstants = GrEditConstants;
   })(window);
-</script>
\ No newline at end of file
+</script>
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.html b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.html
index 2acbab5..2226383 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.html
+++ b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -157,4 +158,4 @@
     <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
   </template>
   <script src="gr-edit-controls.js"></script>
-</dom-module>
\ No newline at end of file
+</dom-module>
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.js b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.js
index e3b3494..8740b0d 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.js
+++ b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
@@ -221,4 +224,4 @@
       return hiddenActions.includes(id) ? 'invisible' : '';
     },
   });
-})();
\ No newline at end of file
+})();
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.html b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.html
index bbb5111..9d85d37 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.html
+++ b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.html b/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.html
index 9863466..fd6aeb0 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.html
+++ b/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -58,4 +59,4 @@
         link>Actions</gr-dropdown>
   </template>
   <script src="gr-edit-file-controls.js"></script>
-</dom-module>
\ No newline at end of file
+</dom-module>
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.js b/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.js
index 6a0ccf5..82010f5 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.js
+++ b/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
@@ -56,4 +59,4 @@
       });
     },
   });
-})();
\ No newline at end of file
+})();
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls_test.html b/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls_test.html
index 27b28fa..12d9e0b 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls_test.html
+++ b/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls_test.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -99,4 +100,4 @@
     assert.equal(element._allFileActions.length, 4);
   });
 });
-</script>
\ No newline at end of file
+</script>
diff --git a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.html b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.html
index 46c69e4..8939a4f 100644
--- a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.html
+++ b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,6 +25,7 @@
 <link rel="import" href="../../plugins/gr-endpoint-param/gr-endpoint-param.html">
 <link rel="import" href="../../shared/gr-button/gr-button.html">
 <link rel="import" href="../../shared/gr-editable-label/gr-editable-label.html">
+<link rel="import" href="../../shared/gr-fixed-panel/gr-fixed-panel.html">
 <link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
 <link rel="import" href="../gr-default-editor/gr-default-editor.html">
 <link rel="import" href="../../../styles/shared-styles.html">
@@ -34,13 +36,9 @@
       :host {
         background-color: var(--view-background-color);
       }
-      .sticky {
+      gr-fixed-panel {
         background-color: #ebf5fb;
         border-bottom: 1px #ddd solid;
-        position: -webkit-sticky;
-        position: sticky;
-        top: 0;
-        width: 100vw;
         z-index: 1;
       }
       header,
@@ -88,7 +86,7 @@
         }
       }
     </style>
-    <div class="sticky">
+    <gr-fixed-panel keep-on-scroll>
       <header>
         <span class="controlGroup">
           <span>Edit mode</span>
@@ -112,7 +110,7 @@
               on-tap="_saveEdit">Save</gr-button>
         </span>
       </header>
-    </div>
+    </gr-fixed-panel>
     <div class="textareaWrapper">
       <gr-endpoint-decorator id="editorEndpoint" name="editor">
         <gr-endpoint-param name="fileContent" value="[[_newContent]]"></gr-endpoint-param>
@@ -124,4 +122,4 @@
     <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
   </template>
   <script src="gr-editor-view.js"></script>
-</dom-module>
\ No newline at end of file
+</dom-module>
diff --git a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.js b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.js
index bd07375..f2d1d76 100644
--- a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.js
+++ b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.html b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.html
index ea87f56..193c2ed 100644
--- a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.html
+++ b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/gr-app-it_test.html b/polygerrit-ui/app/elements/gr-app-it_test.html
index 7b134c1..929156e 100644
--- a/polygerrit-ui/app/elements/gr-app-it_test.html
+++ b/polygerrit-ui/app/elements/gr-app-it_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/gr-app.html b/polygerrit-ui/app/elements/gr-app.html
index 3879495..809ca22 100644
--- a/polygerrit-ui/app/elements/gr-app.html
+++ b/polygerrit-ui/app/elements/gr-app.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -54,6 +55,7 @@
 <link rel="import" href="./settings/gr-cla-view/gr-cla-view.html">
 <link rel="import" href="./settings/gr-registration-dialog/gr-registration-dialog.html">
 <link rel="import" href="./settings/gr-settings-view/gr-settings-view.html">
+<link rel="import" href="./shared/gr-fixed-panel/gr-fixed-panel.html">
 <link rel="import" href="./shared/gr-rest-api-interface/gr-rest-api-interface.html">
 
 <script src="../scripts/util.js"></script>
@@ -62,45 +64,35 @@
   <template>
     <style include="shared-styles">
       :host {
-        /* This needs to be inline-flex so that the app container inherits the
-          width of its children. From here, can use position: sticky to display
-          items that we want to be 'floating' like the header and footer, with
-          a combination of: position: sticky, width=100vw, and left: 0. */
-        display: inline-flex;
+        display: flex;
         min-height: 100%;
         flex-direction: column;
       }
+      gr-fixed-panel {
+        /**
+         * This one should be greater that the z-index in gr-diff-view
+         * because gr-main-header contains overlay.
+         */
+        z-index: 10;
+      }
       gr-main-header,
       footer {
         color: var(--primary-text-color);
       }
+      gr-main-header {
+        background-color: var(--header-background-color);
+        padding: 0 var(--default-horizontal-margin);
+        border-bottom: 1px solid #ddd;
+      }
       gr-main-header.shadow {
         /* Make it obvious for shadow dom testing */
         border-bottom: 1px solid pink;
       }
-      gr-main-header {
-        background-color: var(--header-background-color);
-        border-bottom: 1px solid #ddd;
-        /* The combination of left, width, position allow this to be
-          floating. */
-        left: 0;
-        padding: 0 var(--default-horizontal-margin);
-        position: sticky;
-        width: 100vw;
-        /* Needed for the menu dropdowns to display on top of the sticky
-          headers with z-index of 1.*/
-        z-index: 2;
-      }
       footer {
-        /* The combination of left, width, position allow this to be
-          floating. */
         background-color: var(--footer-background-color);
         display: flex;
-        left: 0;
-        width: 100vw;
         justify-content: space-between;
         padding: .5rem var(--default-horizontal-margin);
-        position: sticky;
         z-index: 100;
       }
       main {
@@ -139,11 +131,13 @@
         color: #b71c1c;
       }
     </style>
-    <gr-main-header
-        id="mainHeader"
-        search-query="{{params.query}}"
-        class$="[[_computeShadowClass(_isShadowDom)]]">
-    </gr-main-header>
+    <gr-fixed-panel id="header">
+      <gr-main-header
+          id="mainHeader"
+          search-query="{{params.query}}"
+          class$="[[_computeShadowClass(_isShadowDom)]]">
+      </gr-main-header>
+    </gr-fixed-panel>
     <main>
       <template is="dom-if" if="[[_showChangeListView]]" restamp="true">
         <gr-change-list-view
diff --git a/polygerrit-ui/app/elements/gr-app.js b/polygerrit-ui/app/elements/gr-app.js
index 99c4d12..3a45575 100644
--- a/polygerrit-ui/app/elements/gr-app.js
+++ b/polygerrit-ui/app/elements/gr-app.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
@@ -182,6 +185,7 @@
       if (this.params.justRegistered) {
         this.$.registration.open();
       }
+      this.$.header.unfloat();
     },
 
     _computeShowGwtUiLink(config) {
@@ -195,6 +199,7 @@
         '_showChangeView',
         '_showDiffView',
         '_showSettingsView',
+        '_showAdminView',
       ];
       for (const showProp of props) {
         this.set(showProp, false);
diff --git a/polygerrit-ui/app/elements/gr-app_test.html b/polygerrit-ui/app/elements/gr-app_test.html
index 320c9f1..f0900aa 100644
--- a/polygerrit-ui/app/elements/gr-app_test.html
+++ b/polygerrit-ui/app/elements/gr-app_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper.html b/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper.html
index c495c94..208f1e8 100644
--- a/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper.html
+++ b/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper.js b/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper.js
index 8db59b5f..df71da6 100644
--- a/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper.js
+++ b/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function(window) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper_test.html b/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper_test.html
index 5dababe..cd59f7d 100644
--- a/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks.html b/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks.html
index 11891c17..252e812 100644
--- a/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks.html
+++ b/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks.js b/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks.js
index 889333b..230be0e 100644
--- a/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks.js
+++ b/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function(window) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks_test.html b/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks_test.html
index f5a7f6f..3dde458 100644
--- a/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.html b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.html
index fc42ae8..50b80d5 100644
--- a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.html
+++ b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.js b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.js
index 16dd8c4..5006461 100644
--- a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.js
+++ b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator_test.html b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator_test.html
index ae6c4b8..0f0fab5 100644
--- a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/plugins/gr-endpoint-param/gr-endpoint-param.html b/polygerrit-ui/app/elements/plugins/gr-endpoint-param/gr-endpoint-param.html
index 1aa9e7c..9d28ac3 100644
--- a/polygerrit-ui/app/elements/plugins/gr-endpoint-param/gr-endpoint-param.html
+++ b/polygerrit-ui/app/elements/plugins/gr-endpoint-param/gr-endpoint-param.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/plugins/gr-endpoint-param/gr-endpoint-param.js b/polygerrit-ui/app/elements/plugins/gr-endpoint-param/gr-endpoint-param.js
index 2833654..cbc3d6a 100644
--- a/polygerrit-ui/app/elements/plugins/gr-endpoint-param/gr-endpoint-param.js
+++ b/polygerrit-ui/app/elements/plugins/gr-endpoint-param/gr-endpoint-param.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper.html b/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper.html
index d62ac99..d34bdef 100644
--- a/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper.html
+++ b/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper.js b/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper.js
index 18eeb87..414abad 100644
--- a/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper.js
+++ b/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function(window) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper_test.html b/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper_test.html
index 43c42a9..709c042 100644
--- a/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.html b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.html
index 2f957af..a83b2ab 100644
--- a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.html
+++ b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.js b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.js
index a4f1f74..51ad0b7 100644
--- a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.js
+++ b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style_test.html b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style_test.html
index bc24c2b..d1893ba 100644
--- a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.html b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.html
index ad4e2b0..8e106cc 100644
--- a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.html
+++ b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.js b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.js
index 497ea9c..982123c 100644
--- a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.js
+++ b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host_test.html b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host_test.html
index d42cb88..ac9e69c 100644
--- a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.html b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.html
index af9ed37..ce0bf1b 100644
--- a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.html
+++ b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.js b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.js
index 8286eae..dd37f84 100644
--- a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.js
+++ b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function(window) {
   'use strict';
   Polymer({
diff --git a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup_test.html b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup_test.html
index 2dbf96d..91386b9 100644
--- a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.html b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.html
index 6bf37de..2fdf28c 100644
--- a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.html
+++ b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.js b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.js
index e62e882..556cfd8 100644
--- a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.js
+++ b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function(window) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface_test.html b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface_test.html
index 7d9dd28..983c795 100644
--- a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-plugin-repo-command.html b/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-plugin-repo-command.html
index 5645c36..e47ba15 100644
--- a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-plugin-repo-command.html
+++ b/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-plugin-repo-command.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api.html b/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api.html
index 6062642..34c9797 100644
--- a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api.html
+++ b/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api.js b/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api.js
index 8ce34a7..45f106d 100644
--- a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api.js
+++ b/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function(window) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api_test.html b/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api_test.html
index 5ef79a9..bb9ae87 100644
--- a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api.html b/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api.html
index 4c57daf..7c916dc 100644
--- a/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api.html
+++ b/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Settings
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api.js b/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api.js
index f33b683..49ff4ce 100644
--- a/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api.js
+++ b/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 The Android Open Source Settings
-//
-// 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.
+/**
+ * @license
+ * Copyright (C) 2017 The Android Open Source Settings
+ *
+ * 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.
+ */
 (function(window) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api_test.html b/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api_test.html
index cbe71fe..cabd26b 100644
--- a/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Settings
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-custom-plugin-header.html b/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-custom-plugin-header.html
index 233e83e..e6e8fa5 100644
--- a/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-custom-plugin-header.html
+++ b/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-custom-plugin-header.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api.html b/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api.html
index 973254a..b84f5b9 100644
--- a/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api.html
+++ b/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api.js b/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api.js
index d57b301..404fb9c 100644
--- a/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api.js
+++ b/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function(window) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api_test.html b/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api_test.html
index 74dff66..a15dfe4 100644
--- a/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.html b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.html
index 5563ab9..912deb9 100644
--- a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.html
+++ b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.js b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.js
index 3cec65a..3ad151a 100644
--- a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.js
+++ b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_test.html b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_test.html
index 82997a5..d5682e0 100644
--- a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.html b/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.html
index 307a2b4..72ea503 100644
--- a/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.html
+++ b/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.js b/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.js
index 4e25523..41595a98 100644
--- a/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.js
+++ b/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list_test.html b/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list_test.html
index 13b8952..56122a9 100644
--- a/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.html b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.html
index 43343de..7e45abc 100644
--- a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.html
+++ b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.js b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.js
index 4d87f9e..7b74096 100644
--- a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.js
+++ b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.html b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.html
index e1753ba..daf9437 100644
--- a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.html b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.html
index a1f5dc5..31715c1 100644
--- a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.html
+++ b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2018 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -50,13 +51,12 @@
       .contributorAgreementButton {
         font-family: var(--font-family-bold);
       }
-      .contributorAgreementAlreadySubmitted {
+      .alreadySubmittedText {
         color: red;
         margin: 0 2em;
         padding: .5em;
       }
-      .agreementsSubmitted,
-      .hideAgreementsTextBox {
+      .alreadySubmittedText.hide {
         display: none;
       }
       main {
@@ -76,10 +76,10 @@
               data-name$="[[item.name]]"
               data-url$="[[item.url]]"
               on-tap="_handleShowAgreement"
-              disabled$="[[_disableAggreements(item, _groups)]]">
+              disabled$="[[_disableAggreements(item, _groups, _signedAgreements)]]">
           <label id="claNewAgreementsLabel">[[item.name]]</label>
         </span>
-        <div class$="contributorAgreementAlreadySubmitted [[_hideAggreements(item, _groups)]]">
+        <div class$="alreadySubmittedText [[_hideAggreements(item, _groups, _signedAgreements)]]">
           Agreement already submitted.
         </div>
         <div class="agreementsUrl">
@@ -104,4 +104,4 @@
     <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
   </template>
   <script src="gr-cla-view.js"></script>
-</dom-module>
\ No newline at end of file
+</dom-module>
diff --git a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.js b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.js
index 39400c64..f34328e 100644
--- a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.js
+++ b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.js
@@ -1,16 +1,19 @@
-// 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.
+/**
+ * @license
+ * 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.
+ */
 (function() {
   'use strict';
 
@@ -23,6 +26,7 @@
       _serverConfig: Object,
       _agreementsText: String,
       _agreementName: String,
+      _signedAgreements: Array,
       _showAgreements: {
         type: Boolean,
         value: false,
@@ -52,6 +56,10 @@
         });
       }));
 
+      promises.push(this.$.restAPI.getAccountAgreements().then(agreements => {
+        this._signedAgreements = agreements || [];
+      }));
+
       return Promise.all(promises);
     },
 
@@ -99,20 +107,20 @@
       return agreements ? 'show' : '';
     },
 
-    _disableAggreements(item, groups) {
-      for (const value of groups) {
-        if (item && item.auto_verify_group &&
-            item.auto_verify_group.name === value.name) {
+    _disableAggreements(item, groups, signedAgreements) {
+      for (const group of groups) {
+        if ((item && item.auto_verify_group &&
+            item.auto_verify_group.id === group.id) ||
+            signedAgreements.find(i => i.name === item.name)) {
           return true;
         }
       }
-
       return false;
     },
 
-    _hideAggreements(item, groups) {
-      return this._disableAggreements(item, groups) ?
-          '' : 'agreementsSubmitted';
+    _hideAggreements(item, groups, signedAgreements) {
+      return this._disableAggreements(item, groups, signedAgreements) ?
+          '' : 'hide';
     },
 
     _disableAgreementsText(text) {
diff --git a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_test.html b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_test.html
index 985fbfa..2304d15 100644
--- a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2018 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -34,39 +35,51 @@
 <script>
   suite('gr-cla-view tests', () => {
     let element;
-    let agreements;
+    const signedAgreements = [{
+      name: 'CLA',
+      description: 'Contributor License Agreement',
+      url: 'static/cla.html',
+    }];
     const auth = {
       name: 'Individual',
       description: 'test-description',
       url: 'static/cla_individual.html',
       auto_verify_group: {
-        url: '#/admin/groups/uuid-bc53f2738ef8ad0b3a4f53846ff59b05822caecb',
+        url: '#/admin/groups/uuid-e9aaddc47f305be7661ad4db9b66f9b707bd19a0',
         options: {
           visible_to_all: true,
         },
         group_id: 20,
         owner: 'CLA Accepted - Individual',
-        owner_id: 'bc53f2738ef8ad0b3a4f53846ff59b05822caecb',
+        owner_id: 'e9aaddc47f305be7661ad4db9b66f9b707bd19a0',
         created_on: '2017-07-31 15:11:04.000000000',
-        id: 'bc53f2738ef8ad0b3a4f53846ff59b05822caecb',
+        id: 'e9aaddc47f305be7661ad4db9b66f9b707bd19a0',
         name: 'CLA Accepted - Individual',
       },
     };
+
     const auth2 = {
       name: 'Individual2',
       description: 'test-description2',
       url: 'static/cla_individual2.html',
       auto_verify_group: {
-        url: '#/admin/groups/uuid-e9aaddc47f305be7661ad4db9b66f9b707bd19a0',
+        url: '#/admin/groups/uuid-bc53f2738ef8ad0b3a4f53846ff59b05822caecb',
         options: {},
         group_id: 21,
         owner: 'CLA Accepted - Individual2',
-        owner_id: 'e9aaddc47f305be7661ad4db9b66f9b707bd19a0',
+        owner_id: 'bc53f2738ef8ad0b3a4f53846ff59b05822caecb',
         created_on: '2017-07-31 15:25:42.000000000',
-        id: 'e9aaddc47f305be7661ad4db9b66f9b707bd19a0',
+        id: 'bc53f2738ef8ad0b3a4f53846ff59b05822caecb',
         name: 'CLA Accepted - Individual2',
       },
     };
+
+    const auth3 = {
+      name: 'CLA',
+      description: 'Contributor License Agreement',
+      url: 'static/cla_individual.html',
+    };
+
     const config = {
       auth: {
         use_contributor_agreements: true,
@@ -76,7 +89,11 @@
             description: 'test-description',
             url: 'static/cla_individual.html',
           },
-        ],
+          {
+            name: 'CLA',
+            description: 'Contributor License Agreement',
+            url: 'static/cla.html',
+          }],
       },
     };
     const config2 = {
@@ -91,91 +108,80 @@
         ],
       },
     };
-    const groups = [
-      {
-        url: 'some url',
-        options: {},
-        description: 'Group 1 description',
-        group_id: 1,
-        owner: 'Administrators',
-        owner_id: '123',
-        id: 'abc',
-        name: 'Individual',
-      },
-      {
-        options: {visible_to_all: true},
-        id: '456',
-        group_id: 2,
-        name: 'Individual 2',
-      },
-      {
-        options: {visible_to_all: true},
-        id: '457',
-        group_id: 3,
-        name: 'CLA Accepted - Individual',
-      },
+    const groups = [{
+      options: {visible_to_all: true},
+      id: 'e9aaddc47f305be7661ad4db9b66f9b707bd19a0',
+      group_id: 3,
+      name: 'CLA Accepted - Individual',
+    },
     ];
 
     setup(done => {
-      agreements = [{
-        url: 'test-agreements.html',
-        description: 'Agreements 1 description',
-        name: 'Agreements 1',
-      }];
-
       stub('gr-rest-api-interface', {
-        getAccountGroups() { return Promise.resolve(agreements); },
+        getConfig() { return Promise.resolve(config); },
+        getAccountGroups() { return Promise.resolve(groups); },
+        getAccountAgreements() { return Promise.resolve(signedAgreements); },
       });
-
       element = fixture('basic');
-
       element.loadData().then(() => { flush(done); });
     });
 
-    test('_disableAggreements equals true', () => {
-      assert.isTrue(element._disableAggreements(auth, groups));
+    test('renders as expected with signed agreement', () => {
+      const agreementSections = Polymer.dom(element.root)
+          .querySelectorAll('.contributorAgreementButton');
+      const agreementSubmittedTexts = Polymer.dom(element.root)
+          .querySelectorAll('.alreadySubmittedText');
+      assert.equal(agreementSections.length, 2);
+      assert.isFalse(agreementSections[0].querySelector('input').disabled);
+      assert.equal(getComputedStyle(agreementSubmittedTexts[0]).display,
+          'none');
+      assert.isTrue(agreementSections[1].querySelector('input').disabled);
+      assert.notEqual(getComputedStyle(agreementSubmittedTexts[1]).display,
+          'none');
     });
 
-    test('_disableAggreements equals false', () => {
-      assert.isFalse(element._disableAggreements(auth2, groups));
+    test('_disableAggreements', () => {
+      // In the auto verify group and have not yet signed agreement
+      assert.isTrue(
+          element._disableAggreements(auth, groups, signedAgreements));
+      // Not in the auto verify group and have not yet signed agreement
+      assert.isFalse(
+          element._disableAggreements(auth2, groups, signedAgreements));
+      // Not in the auto verify group, have signed agreement
+      assert.isTrue(
+          element._disableAggreements(auth3, groups, signedAgreements));
     });
 
-    test('_hideAggreements equals string', () => {
-      assert.equal(element._hideAggreements(auth, groups), '');
+    test('_hideAggreements', () => {
+      // Not in the auto verify group and have not yet signed agreement
+      assert.equal(
+          element._hideAggreements(auth, groups, signedAgreements), '');
+      // In the auto verify group
+      assert.equal(
+          element._hideAggreements(auth2, groups, signedAgreements), 'hide');
+      // Not in the auto verify group, have signed agreement
+      assert.equal(
+          element._hideAggreements(auth3, groups, signedAgreements), '');
     });
 
-    test('_hideAggreements equals agreementsSubmitted', () => {
-      assert.equal(element._hideAggreements(auth2, groups),
-          'agreementsSubmitted');
-    });
-
-    test('_disableAgreementsText equals true', () => {
+    test('_disableAgreementsText', () => {
       assert.isFalse(element._disableAgreementsText('I AGREE'));
-    });
-
-    test('_disableAgreementsText equals true', () => {
       assert.isTrue(element._disableAgreementsText('I DO NOT AGREE'));
     });
 
-    test('_computeHideAgreementClass returns true', () => {
+    test('_computeHideAgreementClass', () => {
       assert.equal(
           element._computeHideAgreementClass(
               auth.name, config.auth.contributor_agreements),
           'hideAgreementsTextBox');
-    });
-
-    test('_computeHideAgreementClass returns undefined', () => {
       assert.isUndefined(
           element._computeHideAgreementClass(
               auth.name, config2.auth.contributor_agreements));
     });
 
-    test('_getAgreementsUrl has http', () => {
+    test('_getAgreementsUrl', () => {
       assert.equal(element._getAgreementsUrl(
           'http://test.org/test.html'), 'http://test.org/test.html');
-    });
-
-    test('_getAgreementsUrl does not have http://', () => {
       assert.equal(element._getAgreementsUrl(
           'test_cla.html'), '/test_cla.html');
     });
diff --git a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.html b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.html
index 00735cf..782100e 100644
--- a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.html
+++ b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2018 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.js b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.js
index dbacfda..86350f9 100644
--- a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.js
+++ b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.js
@@ -1,16 +1,19 @@
-// 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.
+/**
+ * @license
+ * 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_test.html b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_test.html
index e91290f6..42171b7 100644
--- a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2018 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.html b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.html
index 99a0392..6ae8295 100644
--- a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.html
+++ b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.js b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.js
index 2d3f1c3..d08cc90 100644
--- a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.js
+++ b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_test.html b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_test.html
index fdbafdb..e937f8b 100644
--- a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.html b/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.html
index b38509d..7a63605 100644
--- a/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.html
+++ b/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.js b/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.js
index f5bf8bc..78025d1 100644
--- a/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.js
+++ b/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor_test.html b/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor_test.html
index f749130..13b3152 100644
--- a/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.html b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.html
index 017f49f..2c7afd3 100644
--- a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.html
+++ b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.js b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.js
index 8ca8598..0f43563 100644
--- a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.js
+++ b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_test.html b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_test.html
index 812b186..3fa5a36 100644
--- a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.html b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.html
index 515fe4f..1164375 100644
--- a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.html
+++ b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.js b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.js
index 3dc92d1..b3d1396 100644
--- a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.js
+++ b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_test.html b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_test.html
index bbe1555..ca50b2b 100644
--- a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.html b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.html
index 5816288..872e558 100644
--- a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.html
+++ b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.js b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.js
index 9c70edd..da6ab28 100644
--- a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.js
+++ b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_test.html b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_test.html
index c6bf764..c77a1b9 100644
--- a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.html b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.html
index 6805885..aa42623 100644
--- a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.html
+++ b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.js b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.js
index 26a2470..aa83bf7 100644
--- a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.js
+++ b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor_test.html b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor_test.html
index 5964578..c8a54b6 100644
--- a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.html b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.html
index 1b3d9d4..4db12ec 100644
--- a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.html
+++ b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.js b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.js
index dace2ca..051668c 100644
--- a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.js
+++ b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.html b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.html
index 15b4fa2..e4560ff 100644
--- a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.html b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.html
index 97fbf0a..b61c7e0 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.html
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.js b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.js
index e4f5d24..0ee1b28 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.js
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-menu-item.html b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-menu-item.html
index ff71d3f..3b47190 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-menu-item.html
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-menu-item.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-menu-item.js b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-menu-item.js
index 797990d..38147cd 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-menu-item.js
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-menu-item.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.html b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.html
index 416c426..64dd506 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.html
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.js b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.js
index 912712c..117321d 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.js
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.html b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.html
index c8ed0f2..c42cb5f 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.html b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.html
index 1afd255..b1b91cc 100644
--- a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.html
+++ b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.js b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.js
index fb868e8..874173a 100644
--- a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.js
+++ b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor_test.html b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor_test.html
index 4273f7a..8607948 100644
--- a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.html b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.html
index e3be10d..0b8c331 100644
--- a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.html
+++ b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.js b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.js
index 40d1e36..ebf61db 100644
--- a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.js
+++ b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor_test.html b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor_test.html
index fbc6217..e018e42 100644
--- a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.html b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.html
index de92b97..ebbc7f5 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.html
+++ b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.js b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.js
index b2cca89..880cbc0 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.js
+++ b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 (function() {
   'use strict';
diff --git a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.html b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.html
index 2a79945..fe77db2 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.html
+++ b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.js b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.js
index c75be10..5b1b975 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.js
+++ b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.html b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.html
index 3087b0e..288a670 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.html b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.html
index 785d509..bea8d27 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.html
+++ b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.js b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.js
index 061e32b..faaf9c3 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.js
+++ b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_test.html b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_test.html
index 0c9661f..6d1831e 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.html b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.html
index bebb1e8..0e6a000 100644
--- a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.html
+++ b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.js b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.js
index bfe7c25..e7c8b2c 100644
--- a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.js
+++ b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert_test.html b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert_test.html
index 79960d4..095e640 100644
--- a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.html b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.html
index 83fb7cb..ef9ed4e 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.html
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.js b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.js
index 431ac0e..0c4d8f1 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.js
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown_test.html b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown_test.html
index 1995688..67a2ac4 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.html b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.html
index 7db3e90..971780e 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.html
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js
index 66a50f0..287ccdd 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html
index dba0d6c..dfb0a0d 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.html b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.html
index 4095d3e..fc029ce 100644
--- a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.html
+++ b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.js b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.js
index 1252f7d..f559148 100644
--- a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.js
+++ b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.html b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.html
index 8187471..333f0e8 100644
--- a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-button/gr-button.html b/polygerrit-ui/app/elements/shared/gr-button/gr-button.html
index 579bc50..6dd197d 100644
--- a/polygerrit-ui/app/elements/shared/gr-button/gr-button.html
+++ b/polygerrit-ui/app/elements/shared/gr-button/gr-button.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-button/gr-button.js b/polygerrit-ui/app/elements/shared/gr-button/gr-button.js
index 7b62fb3..6ac16cc7 100644
--- a/polygerrit-ui/app/elements/shared/gr-button/gr-button.js
+++ b/polygerrit-ui/app/elements/shared/gr-button/gr-button.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-button/gr-button_test.html b/polygerrit-ui/app/elements/shared/gr-button/gr-button_test.html
index c0ceb33..ed0da2e 100644
--- a/polygerrit-ui/app/elements/shared/gr-button/gr-button_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-button/gr-button_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.html b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.html
index 6ed01cf..5e56db1 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.html
+++ b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.js b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.js
index 96c6cd2..9646735 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.js
+++ b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star_test.html b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star_test.html
index 0ab1954..f24b45c 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.html b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.html
index eab0173..e256bf3 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.html
+++ b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.js b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.js
index cd27a28..2832fa7 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.js
+++ b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_test.html b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_test.html
index 212296f..f73fc02 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-confirm-dialog/gr-confirm-dialog.html b/polygerrit-ui/app/elements/shared/gr-confirm-dialog/gr-confirm-dialog.html
index 968143a..cb21bd2 100644
--- a/polygerrit-ui/app/elements/shared/gr-confirm-dialog/gr-confirm-dialog.html
+++ b/polygerrit-ui/app/elements/shared/gr-confirm-dialog/gr-confirm-dialog.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-confirm-dialog/gr-confirm-dialog.js b/polygerrit-ui/app/elements/shared/gr-confirm-dialog/gr-confirm-dialog.js
index 8916296..8ddb85d 100644
--- a/polygerrit-ui/app/elements/shared/gr-confirm-dialog/gr-confirm-dialog.js
+++ b/polygerrit-ui/app/elements/shared/gr-confirm-dialog/gr-confirm-dialog.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-confirm-dialog/gr-confirm-dialog_test.html b/polygerrit-ui/app/elements/shared/gr-confirm-dialog/gr-confirm-dialog_test.html
index a2ae160..8300dd6 100644
--- a/polygerrit-ui/app/elements/shared/gr-confirm-dialog/gr-confirm-dialog_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-confirm-dialog/gr-confirm-dialog_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.html b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.html
index e52ad39..d1d9b33 100644
--- a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.html
+++ b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.js b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.js
index 6a46ae0..cd8cb00 100644
--- a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.js
+++ b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.html b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.html
index 13d8b9d..c865917 100644
--- a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-count-string-formatter/gr-count-string-formatter.html b/polygerrit-ui/app/elements/shared/gr-count-string-formatter/gr-count-string-formatter.html
index 832747e..b69c61aa 100644
--- a/polygerrit-ui/app/elements/shared/gr-count-string-formatter/gr-count-string-formatter.html
+++ b/polygerrit-ui/app/elements/shared/gr-count-string-formatter/gr-count-string-formatter.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -54,4 +55,4 @@
     };
     window.GrCountStringFormatter = GrCountStringFormatter;
   })(window);
-</script>
\ No newline at end of file
+</script>
diff --git a/polygerrit-ui/app/elements/shared/gr-count-string-formatter/gr-count-string-formatter_test.html b/polygerrit-ui/app/elements/shared/gr-count-string-formatter/gr-count-string-formatter_test.html
index f33db80..e4d896b 100644
--- a/polygerrit-ui/app/elements/shared/gr-count-string-formatter/gr-count-string-formatter_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-count-string-formatter/gr-count-string-formatter_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager.html b/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager.html
index f213312..d619b18 100644
--- a/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager.html
+++ b/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager.js b/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager.js
index c0ea5a8..f750cd2 100644
--- a/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager.js
+++ b/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
@@ -262,13 +265,15 @@
      * @return {boolean}
      */
     _targetIsVisible(top) {
+      const dims = this._getWindowDims();
       return this.scrollBehavior === ScrollBehavior.KEEP_VISIBLE &&
-          top > window.pageYOffset &&
-          top < window.pageYOffset + window.innerHeight;
+          top > dims.pageYOffset &&
+          top < dims.pageYOffset + dims.innerHeight;
     },
 
     _calculateScrollToValue(top, target) {
-      return top - (window.innerHeight / 3) + (target.offsetHeight / 2);
+      const dims = this._getWindowDims();
+      return top - (dims.innerHeight / 3) + (target.offsetHeight / 2);
     },
 
     _scrollToTarget() {
@@ -276,6 +281,7 @@
         return;
       }
 
+      const dims = this._getWindowDims();
       const top = this._getTop(this.target);
       const bottomIsVisible = this._targetHeight ?
           this._targetIsVisible(top + this._targetHeight) : true;
@@ -286,7 +292,7 @@
         // would get scrolled to is higher up than the current position. this
         // woulld cause less of the target content to be displayed than is
         // already.
-        if (bottomIsVisible || scrollToValue < window.scrollY) {
+        if (bottomIsVisible || scrollToValue < dims.scrollY) {
           return;
         }
       }
@@ -295,7 +301,16 @@
       // instead of half the inner height feels a bit better otherwise the
       // element appears to be below the center of the window even when it
       // isn't.
-      window.scrollTo(0, scrollToValue);
+      window.scrollTo(dims.scrollX, scrollToValue);
+    },
+
+    _getWindowDims() {
+      return {
+        scrollX: window.scrollX,
+        scrollY: window.scrollY,
+        innerHeight: window.innerHeight,
+        pageYOffset: window.pageYOffset,
+      };
     },
   });
 })();
diff --git a/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager_test.html b/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager_test.html
index 5a4b8ba..adbe618 100644
--- a/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-cursor-manager/gr-cursor-manager_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -222,17 +223,13 @@
       });
 
       test('Called when top and bottom not visible', () => {
-        sandbox.stub(element, '_targetIsVisible', () => {
-          return false;
-        });
+        sandbox.stub(element, '_targetIsVisible').returns(false);
         element._scrollToTarget();
         assert.isTrue(scrollStub.called);
       });
 
       test('Not called when top and bottom visible', () => {
-        sandbox.stub(element, '_targetIsVisible', () => {
-          return true;
-        });
+        sandbox.stub(element, '_targetIsVisible').returns(true);
         element._scrollToTarget();
         assert.isFalse(scrollStub.called);
       });
@@ -240,26 +237,44 @@
       test('Called when top is visible, bottom is not, scroll is lower', () => {
         const visibleStub = sandbox.stub(element, '_targetIsVisible',
             () => visibleStub.callCount === 2);
-        window.scrollY = 15;
-        sandbox.stub(element, '_calculateScrollToValue', () => {
-          return 20;
+        sandbox.stub(element, '_getWindowDims').returns({
+          scrollX: 123,
+          scrollY: 15,
+          innerHeight: 1000,
+          pageYOffset: 0,
         });
+        sandbox.stub(element, '_calculateScrollToValue').returns(20);
         element._scrollToTarget();
         assert.isTrue(scrollStub.called);
+        assert.isTrue(scrollStub.calledWithExactly(123, 20));
         assert.equal(visibleStub.callCount, 2);
       });
 
       test('Called when top is visible, bottom not, scroll is higher', () => {
         const visibleStub = sandbox.stub(element, '_targetIsVisible',
             () => visibleStub.callCount === 2);
-        window.scrollY = 25;
-        sandbox.stub(element, '_calculateScrollToValue', () => {
-          return 20;
+        sandbox.stub(element, '_getWindowDims').returns({
+          scrollX: 123,
+          scrollY: 25,
+          innerHeight: 1000,
+          pageYOffset: 0,
         });
+        sandbox.stub(element, '_calculateScrollToValue').returns(20);
         element._scrollToTarget();
         assert.isFalse(scrollStub.called);
         assert.equal(visibleStub.callCount, 2);
       });
+
+      test('_calculateScrollToValue', () => {
+        sandbox.stub(element, '_getWindowDims').returns({
+          scrollX: 123,
+          scrollY: 25,
+          innerHeight: 300,
+          pageYOffset: 0,
+        });
+        assert.equal(element._calculateScrollToValue(1000, {offsetHeight: 10}),
+            905);
+      });
     });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.html b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.html
index fb41ca6..99492d7 100644
--- a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.html
+++ b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.js b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.js
index 3f7b8db..3417a0d 100644
--- a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.js
+++ b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.html b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.html
index b418a42..ad4d0da 100644
--- a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.html b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.html
index 0f3a469..689119f 100644
--- a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.html
+++ b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.js b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.js
index f2f218b..8f513cb 100644
--- a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.js
+++ b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_test.html b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_test.html
index 41ef8f3..4fe5569 100644
--- a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.html b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.html
index 9867541..ed2586a 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.html
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.js b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.js
index d4225d9..40d8811 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.js
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list_test.html b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list_test.html
index d3c6d83..87fd8de 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.html b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.html
index 62da3bb..ca9c2baa 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.html
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.js b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.js
index 90de1ea..3e05c2b 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.js
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.html b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.html
index ab31f7c..adb89d8 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.html b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.html
index cd7fa1c..6cd87f5 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.html
+++ b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.js b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.js
index 846a272..f567d39 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.js
+++ b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.html b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.html
index b306703..cc44d9b 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.html b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.html
index 92ea347..8addfb6 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.html
+++ b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
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 94a6b64..f943b8e 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
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
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 ec5b64a..058654b 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
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-fixed-panel/gr-fixed-panel.html b/polygerrit-ui/app/elements/shared/gr-fixed-panel/gr-fixed-panel.html
new file mode 100644
index 0000000..674ff97
--- /dev/null
+++ b/polygerrit-ui/app/elements/shared/gr-fixed-panel/gr-fixed-panel.html
@@ -0,0 +1,51 @@
+<!--
+@license
+Copyright (C) 2017 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.
+-->
+
+<link rel="import" href="../../../bower_components/polymer/polymer.html">
+<link rel="import" href="../../../styles/shared-styles.html">
+
+<dom-module id="gr-fixed-panel">
+  <template>
+    <style include="shared-styles">
+      :host {
+        display: block;
+        min-height: var(--header-height);
+        position: relative;
+      }
+      header {
+        background: inherit;
+        border: inherit;
+        display: inline;
+        height: inherit;
+      }
+      .floating {
+        left: 0;
+        position: fixed;
+        width: 100%;
+        will-change: top;
+      }
+      .fixedAtTop {
+        border-bottom: 1px solid #a4a4a4;
+        box-shadow: 0 4px 4px rgba(0,0,0,0.1);
+      }
+    </style>
+    <header id="header" class$="[[_computeHeaderClass(_headerFloating, _topLast)]]">
+      <slot></slot>
+    </header>
+  </template>
+  <script src="gr-fixed-panel.js"></script>
+</dom-module>
diff --git a/polygerrit-ui/app/elements/shared/gr-fixed-panel/gr-fixed-panel.js b/polygerrit-ui/app/elements/shared/gr-fixed-panel/gr-fixed-panel.js
new file mode 100644
index 0000000..ce43031
--- /dev/null
+++ b/polygerrit-ui/app/elements/shared/gr-fixed-panel/gr-fixed-panel.js
@@ -0,0 +1,197 @@
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
+(function() {
+  'use strict';
+
+  Polymer({
+    is: 'gr-fixed-panel',
+
+    properties: {
+      floatingDisabled: Boolean,
+      readyForMeasure: {
+        type: Boolean,
+        observer: '_readyForMeasureObserver',
+      },
+      keepOnScroll: {
+        type: Boolean,
+        value: false,
+      },
+      _isMeasured: {
+        type: Boolean,
+        value: false,
+      },
+
+      /**
+       * Initial offset from the top of the document, in pixels.
+       */
+      _topInitial: Number,
+
+      /**
+       * Current offset from the top of the window, in pixels.
+       */
+      _topLast: Number,
+
+      _headerHeight: Number,
+      _headerFloating: {
+        type: Boolean,
+        value: false,
+      },
+      _observer: {
+        type: Object,
+        value: null,
+      },
+      _webComponentsReady: Boolean,
+    },
+
+    attached() {
+      if (this.floatingDisabled) {
+        return;
+      }
+      // Enable content measure unless blocked by param.
+      if (this.readyForMeasure !== false) {
+        this.readyForMeasure = true;
+      }
+      this.listen(window, 'resize', 'update');
+      this.listen(window, 'scroll', '_updateOnScroll');
+      this._observer = new MutationObserver(this.update.bind(this));
+      this._observer.observe(this.$.header, {childList: true, subtree: true});
+    },
+
+    detached() {
+      this.unlisten(window, 'scroll', '_updateOnScroll');
+      this.unlisten(window, 'resize', 'update');
+      if (this._observer) {
+        this._observer.disconnect();
+      }
+    },
+
+    _readyForMeasureObserver(readyForMeasure) {
+      if (readyForMeasure) {
+        this.update();
+      }
+    },
+
+    _computeHeaderClass(headerFloating, topLast) {
+      const fixedAtTop = this.keepOnScroll && topLast === 0;
+      return [
+        headerFloating ? 'floating' : '',
+        fixedAtTop ? 'fixedAtTop' : '',
+      ].join(' ');
+    },
+
+    _getScrollY() {
+      return window.scrollY;
+    },
+
+    unfloat() {
+      if (this.floatingDisabled) {
+        return;
+      }
+      this.$.header.style.top = '';
+      this._headerFloating = false;
+      this.updateStyles({'--header-height': ''});
+    },
+
+    update() {
+      this.debounce('update', () => {
+        this._updateDebounced();
+      }, 100);
+    },
+
+    _updateOnScroll() {
+      this.debounce('update', () => {
+        this._updateDebounced();
+      });
+    },
+
+    _updateDebounced() {
+      if (this.floatingDisabled) {
+        return;
+      }
+      this._isMeasured = false;
+      this._maybeFloatHeader();
+      this._reposition();
+    },
+
+    _reposition() {
+      if (!this._headerFloating) {
+        return;
+      }
+      const header = this.$.header;
+      const scrollY = this._topInitial - this._getScrollY();
+      let newTop;
+      if (this.keepOnScroll) {
+        if (scrollY > 0) {
+          // Reposition to imitate natural scrolling.
+          newTop = scrollY;
+        } else {
+          newTop = 0;
+        }
+      } else if (scrollY > -this._headerHeight ||
+          this._topLast < -this._headerHeight) {
+        // Allow to scroll away, but ignore when far behind the edge.
+        newTop = scrollY;
+      } else {
+        newTop = -this._headerHeight;
+      }
+      if (this._topLast !== newTop) {
+        if (newTop === undefined) {
+          header.style.top = '';
+        } else {
+          header.style.top = newTop + 'px';
+        }
+        this._topLast = newTop;
+      }
+    },
+
+    _measure() {
+      if (this._isMeasured) {
+        return; // Already measured.
+      }
+      const rect = this.$.header.getBoundingClientRect();
+      if (rect.height === 0 && rect.width === 0) {
+        return; // Not ready for measurement yet.
+      }
+      const top = document.body.scrollTop + rect.top;
+      this._topLast = top;
+      this._headerHeight = rect.height;
+      this._topInitial =
+        this.getBoundingClientRect().top + document.body.scrollTop;
+      this._isMeasured = true;
+    },
+
+    _isFloatingNeeded() {
+      return this.keepOnScroll ||
+        document.body.scrollWidth > document.body.clientWidth;
+    },
+
+    _maybeFloatHeader() {
+      if (!this._isFloatingNeeded()) {
+        return;
+      }
+      this._measure();
+      if (this._isMeasured) {
+        this._floatHeader();
+      }
+    },
+
+    _floatHeader() {
+      this.updateStyles({'--header-height': this._headerHeight + 'px'});
+      this._headerFloating = true;
+    },
+  });
+})();
diff --git a/polygerrit-ui/app/elements/shared/gr-fixed-panel/gr-fixed-panel_test.html b/polygerrit-ui/app/elements/shared/gr-fixed-panel/gr-fixed-panel_test.html
new file mode 100644
index 0000000..ec3ebe2
--- /dev/null
+++ b/polygerrit-ui/app/elements/shared/gr-fixed-panel/gr-fixed-panel_test.html
@@ -0,0 +1,112 @@
+<!DOCTYPE html>
+<!--
+@license
+Copyright (C) 2017 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.
+-->
+
+<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+<title>gr-fixed-panel</title>
+
+<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
+<script src="../../../bower_components/web-component-tester/browser.js"></script>
+<link rel="import" href="../../../test/common-test-setup.html"/>
+<link rel="import" href="gr-fixed-panel.html">
+
+<script>void(0);</script>
+
+<test-fixture id="basic">
+  <template>
+    <gr-fixed-panel>
+      <div style="height: 100px"></div>
+    </gr-fixed-panel>
+  </template>
+</test-fixture>
+
+<script>
+  suite('gr-fixed-panel', () => {
+    let element;
+    let sandbox;
+
+    setup(() => {
+      sandbox = sinon.sandbox.create();
+      element = fixture('basic');
+      element.readyForMeasure = true;
+    });
+
+    teardown(() => {
+      sandbox.restore();
+    });
+
+    test('can be disabled with floatingDisabled', () => {
+      element.floatingDisabled = true;
+      sandbox.stub(element, '_reposition');
+      window.dispatchEvent(new CustomEvent('resize'));
+      element.flushDebouncer('update');
+      assert.isFalse(element._reposition.called);
+    });
+
+    test('header is the height of the content', () => {
+      assert.equal(element.getBoundingClientRect().height, 100);
+    });
+
+    test('scroll triggers _reposition', () => {
+      sandbox.stub(element, '_reposition');
+      window.dispatchEvent(new CustomEvent('scroll'));
+      element.flushDebouncer('update');
+      assert.isTrue(element._reposition.called);
+    });
+
+    suite('_reposition', () => {
+      const getHeaderTop = function() {
+        return element.$.header.style.top;
+      };
+
+      const emulateScrollY = function(distance) {
+        element._getScrollY.returns(distance);
+        element._updateDebounced();
+        element.flushDebouncer('scroll');
+      };
+
+      setup(() => {
+        element._headerTopInitial = 10;
+        sandbox.stub(element, '_getScrollY').returns(0);
+      });
+
+      test('scrolls header along with document', () => {
+        emulateScrollY(20);
+        assert.equal(getHeaderTop(), '-12px');
+      });
+
+      test('does not stick to the top by default', () => {
+        emulateScrollY(150);
+        assert.equal(getHeaderTop(), '-100px');
+      });
+
+      test('sticks to the top if enabled', () => {
+        element.keepOnScroll = true;
+        emulateScrollY(120);
+        assert.equal(getHeaderTop(), '0px');
+      });
+
+      test('drops a shadow when fixed to the top', () => {
+        element.keepOnScroll = true;
+        emulateScrollY(5);
+        assert.isFalse(element.$.header.classList.contains('fixedAtTop'));
+        emulateScrollY(120);
+        assert.isTrue(element.$.header.classList.contains('fixedAtTop'));
+      });
+    });
+  });
+</script>
diff --git a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.html b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.html
index 1ef5a0c..3995595 100644
--- a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.html
+++ b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.js b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.js
index d2392e1..4e68d42 100644
--- a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.js
+++ b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.html b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.html
index b1c536f..ad036c5 100644
--- a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.html b/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.html
index 06aa43b..a3e1c02 100644
--- a/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.html
+++ b/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -42,7 +43,7 @@
       <!-- This is a custom PolyGerrit SVG -->
       <g id="side-by-side"><path d="M17.1578947,10.8888889 L2.84210526,10.8888889 C2.37894737,10.8888889 2,11.2888889 2,11.7777778 L2,17.1111111 C2,17.6 2.37894737,18 2.84210526,18 L17.1578947,18 C17.6210526,18 18,17.6 18,17.1111111 L18,11.7777778 C18,11.2888889 17.6210526,10.8888889 17.1578947,10.8888889 Z M17.1578947,2 L2.84210526,2 C2.37894737,2 2,2.4 2,2.88888889 L2,8.22222222 C2,8.71111111 2.37894737,9.11111111 2.84210526,9.11111111 L17.1578947,9.11111111 C17.6210526,9.11111111 18,8.71111111 18,8.22222222 L18,2.88888889 C18,2.4 17.6210526,2 17.1578947,2 Z M16.1973628,2 L2.78874238,2 C2.35493407,2 2,2.4 2,2.88888889 L2,8.22222222 C2,8.71111111 2.35493407,9.11111111 2.78874238,9.11111111 L16.1973628,9.11111111 C16.6311711,9.11111111 16.9861052,8.71111111 16.9861052,8.22222222 L16.9861052,2.88888889 C16.9861052,2.4 16.6311711,2 16.1973628,2 Z" id="Shape" transform="scale(1.2) translate(10.000000, 10.000000) rotate(-90.000000) translate(-10.000000, -10.000000)"/></g>
       <!-- This is a custom PolyGerrit SVG -->
-      <g id="unified"><path d="M4,2 L17,2 C18.1045695,2 19,2.8954305 19,4 L19,16 C19,17.1045695 18.1045695,18 17,18 L4,18 C2.8954305,18 2,17.1045695 2,16 L2,4 L2,4 C2,2.8954305 2.8954305,2 4,2 L4,2 Z M4,7 L4,9 L17,9 L17,7 L4,7 Z M4,11 L4,13 L17,13 L17,11 L4,11 Z" id="Combined-Shape" transform="scale(1.2)"/></g>
+      <g id="unified"><path d="M4,2 L17,2 C18.1045695,2 19,2.8954305 19,4 L19,16 C19,17.1045695 18.1045695,18 17,18 L4,18 C2.8954305,18 2,17.1045695 2,16 L2,4 L2,4 C2,2.8954305 2.8954305,2 4,2 L4,2 Z M4,7 L4,9 L17,9 L17,7 L4,7 Z M4,11 L4,13 L17,13 L17,11 L4,11 Z" id="Combined-Shape" transform="scale(1.12, 1.2)"/></g>
       <!-- This is a custom PolyGerrit SVG -->
       <g id="content-copy"><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></g>
       <!-- This is a custom PolyGerrit SVG -->
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context.js
index 7810d7d..9331173 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function(window) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context_test.html
index 55ca90f..cd86fa9 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api.js
index 6350c54..cb8409e 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function(window) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api_test.html
index a19df85..bfb8b47 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.js
index 7be007f..e0e3e9a 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function(window) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.html
index e48a352..de1ed41 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api.js
index 376baff..7ab8f2a 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function(window) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api_test.html
index c21424b..278f95a 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.html
index a489e2c..a5adb1d 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.js
index d974b62..3ed6386 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html
index 5ad3895..8867b9d 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context.js
index f0c42f0..84b7f0a 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function(window) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context_test.html
index 072a781..7c18a99 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints.js
index 9374ccf..9931f72 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function(window) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.html
index cb8b964..b00b5ac 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-rest-api.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-rest-api.js
index d04a758..0e65065 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-rest-api.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-rest-api.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function(window) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-rest-api_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-rest-api_test.html
index fd5da3f..80460d6 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-rest-api_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-rest-api_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js
index cbf896a..efb88401 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function(window) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-label/gr-label.html b/polygerrit-ui/app/elements/shared/gr-label/gr-label.html
index c448880..fe290b7 100644
--- a/polygerrit-ui/app/elements/shared/gr-label/gr-label.html
+++ b/polygerrit-ui/app/elements/shared/gr-label/gr-label.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-label/gr-label.js b/polygerrit-ui/app/elements/shared/gr-label/gr-label.js
index 37e1f77..0de0881 100644
--- a/polygerrit-ui/app/elements/shared/gr-label/gr-label.js
+++ b/polygerrit-ui/app/elements/shared/gr-label/gr-label.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text.html b/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text.html
index 8f88b6a..91866e5 100644
--- a/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text.html
+++ b/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text.js b/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text.js
index 0e13563..0dc3a7d 100644
--- a/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text.js
+++ b/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text_test.html b/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text_test.html
index d0d5a33..16eb960 100644
--- a/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.html b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.html
index ca0b90a..41988de 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.html
+++ b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.js b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.js
index bfb8dbb..f8f29b8 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.js
+++ b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip_test.html b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip_test.html
index d707d10..eb57428 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.html b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.html
index a0d9233..13443ee 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.html
+++ b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.js b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.js
index 0f346f4..2c45311 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.js
+++ b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_test.html b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_test.html
index 52a7de0..5978e37 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-text/link-text-parser.js b/polygerrit-ui/app/elements/shared/gr-linked-text/link-text-parser.js
index 8a489f4..a84411f 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-text/link-text-parser.js
+++ b/polygerrit-ui/app/elements/shared/gr-linked-text/link-text-parser.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view.html b/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view.html
index aad8d91..d295770 100644
--- a/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view.html
+++ b/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view.js b/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view.js
index e9ee51a..53691fc 100644
--- a/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view.js
+++ b/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view_test.html b/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view_test.html
index 680bf93..d1cf80a 100644
--- a/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.html b/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.html
index 9067114..e9bfb6d 100644
--- a/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.html
+++ b/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.js b/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.js
index ebf2f02..6df04a2 100644
--- a/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.js
+++ b/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay_test.html b/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay_test.html
index 3f427ca..ee05b69 100644
--- a/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.html b/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.html
index cef02c0..7806b8f 100644
--- a/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.html
+++ b/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.js b/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.js
index 4c38e3f..909cb9a 100644
--- a/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.js
+++ b/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav_test.html b/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav_test.html
index 7e426d7..428bab3 100644
--- a/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-auth.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-auth.js
index 4179b46..43e3922 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-auth.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-auth.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function(window) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-auth_test.html b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-auth_test.html
index c254e62..a571be9 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-auth_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-auth_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-etag-decorator.html b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-etag-decorator.html
index d0306b8..c5a0dfe 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-etag-decorator.html
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-etag-decorator.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-etag-decorator.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-etag-decorator.js
index 3570081..f72c7cc 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-etag-decorator.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-etag-decorator.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function(window) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-etag-decorator_test.html b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-etag-decorator_test.html
index 77edae7..09ae1da 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-etag-decorator_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-etag-decorator_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.html b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.html
index 0ba6f97..562980c 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.html
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
index 27f330e..305fc6f 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
@@ -238,18 +241,18 @@
       return this.fetchJSON('/config/server/info');
     },
 
-    getRepo(repo) {
+    getRepo(repo, opt_errFn) {
       // TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
       // supports it.
       return this._fetchSharedCacheURL(
-          '/projects/' + encodeURIComponent(repo));
+          '/projects/' + encodeURIComponent(repo), opt_errFn);
     },
 
-    getProjectConfig(repo) {
+    getProjectConfig(repo, opt_errFn) {
       // TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
       // supports it.
       return this._fetchSharedCacheURL(
-          '/projects/' + encodeURIComponent(repo) + '/config');
+          '/projects/' + encodeURIComponent(repo) + '/config', opt_errFn);
     },
 
     getRepoAccess(repo) {
@@ -259,11 +262,12 @@
           '/access/?project=' + encodeURIComponent(repo));
     },
 
-    getRepoDashboards(repo) {
+    getRepoDashboards(repo, opt_errFn) {
       // TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
       // supports it.
       return this._fetchSharedCacheURL(
-          `/projects/${encodeURIComponent(repo)}/dashboards?inherited`);
+          `/projects/${encodeURIComponent(repo)}/dashboards?inherited`,
+          opt_errFn);
     },
 
     saveRepoConfig(repo, config, opt_errFn, opt_ctx) {
@@ -309,9 +313,9 @@
           opt_ctx);
     },
 
-    getGroupConfig(group) {
+    getGroupConfig(group, opt_errFn) {
       const encodeName = encodeURIComponent(group);
-      return this.fetchJSON(`/groups/${encodeName}/detail`);
+      return this.fetchJSON(`/groups/${encodeName}/detail`, opt_errFn);
     },
 
     /**
@@ -393,9 +397,9 @@
           .then(configs => configs.hasOwnProperty(groupName));
     },
 
-    getGroupMembers(groupName) {
+    getGroupMembers(groupName, opt_errFn) {
       const encodeName = encodeURIComponent(groupName);
-      return this.send('GET', `/groups/${encodeName}/members/`)
+      return this.send('GET', `/groups/${encodeName}/members/`, null, opt_errFn)
           .then(response => this.getResponseObject(response));
     },
 
@@ -426,8 +430,9 @@
       return this.send('PUT', `/groups/${encodeId}/options`, options);
     },
 
-    getGroupAuditLog(group) {
-      return this._fetchSharedCacheURL('/groups/' + group + '/log.audit');
+    getGroupAuditLog(group, opt_errFn) {
+      return this._fetchSharedCacheURL(
+          '/groups/' + group + '/log.audit', opt_errFn);
     },
 
     saveGroupMembers(groupName, groupMembers) {
@@ -694,7 +699,7 @@
     },
 
     getAccountAgreements() {
-      return this._fetchSharedCacheURL('/accounts/self/agreements');
+      return this.fetchJSON('/accounts/self/agreements');
     },
 
     saveAccountAgreement(name) {
@@ -1105,6 +1110,13 @@
           opt_errFn, null, params);
     },
 
+    /**
+     * @param {number|string} changeNum
+     */
+    getChangeIncludedIn(changeNum) {
+      return this._getChangeURLAndFetch(changeNum, '/in', null);
+    },
+
     _computeFilter(filter) {
       if (filter && filter.startsWith('^')) {
         filter = '&r=' + encodeURIComponent(filter);
@@ -1160,9 +1172,10 @@
      * @param {string} repo
      * @param {number} reposBranchesPerPage
      * @param {number=} opt_offset
+     * @param {?function(?Response, string=)=} opt_errFn
      * @return {!Promise<?Object>}
      */
-    getRepoBranches(filter, repo, reposBranchesPerPage, opt_offset) {
+    getRepoBranches(filter, repo, reposBranchesPerPage, opt_offset, opt_errFn) {
       const offset = opt_offset || 0;
 
       // TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
@@ -1170,7 +1183,8 @@
       return this.fetchJSON(
           `/projects/${encodeURIComponent(repo)}/branches` +
           `?n=${reposBranchesPerPage + 1}&S=${offset}` +
-          this._computeFilter(filter)
+          this._computeFilter(filter),
+          opt_errFn
       );
     },
 
@@ -1179,9 +1193,10 @@
      * @param {string} repo
      * @param {number} reposTagsPerPage
      * @param {number=} opt_offset
+     * @param {?function(?Response, string=)=} opt_errFn
      * @return {!Promise<?Object>}
      */
-    getRepoTags(filter, repo, reposTagsPerPage, opt_offset) {
+    getRepoTags(filter, repo, reposTagsPerPage, opt_offset, opt_errFn) {
       const offset = opt_offset || 0;
 
       // TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
@@ -1189,7 +1204,8 @@
       return this.fetchJSON(
           `/projects/${encodeURIComponent(repo)}/tags` +
           `?n=${reposTagsPerPage + 1}&S=${offset}` +
-          this._computeFilter(filter)
+          this._computeFilter(filter),
+          opt_errFn
       );
     },
 
@@ -1197,21 +1213,26 @@
      * @param {string} filter
      * @param {number} pluginsPerPage
      * @param {number=} opt_offset
+     * @param {?function(?Response, string=)=} opt_errFn
      * @return {!Promise<?Object>}
      */
-    getPlugins(filter, pluginsPerPage, opt_offset) {
+    getPlugins(filter, pluginsPerPage, opt_offset, opt_errFn) {
       const offset = opt_offset || 0;
 
       return this.fetchJSON(
           `/plugins/?all&n=${pluginsPerPage + 1}&S=${offset}` +
-          this._computeFilter(filter)
+          this._computeFilter(filter),
+          opt_errFn
       );
     },
 
-    getRepoAccessRights(repoName) {
+    getRepoAccessRights(repoName, opt_errFn) {
       // TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
       // supports it.
-      return this.fetchJSON(`/projects/${encodeURIComponent(repoName)}/access`);
+      return this.fetchJSON(
+          `/projects/${encodeURIComponent(repoName)}/access`,
+          opt_errFn
+      );
     },
 
     setRepoAccessRights(repoName, repoInfo) {
@@ -1403,9 +1424,10 @@
      * @param {string=} opt_topic
      * @param {boolean=} opt_isPrivate
      * @param {boolean=} opt_workInProgress
+     * @param {string=} opt_baseChange
      */
     createChange(project, branch, subject, opt_topic, opt_isPrivate,
-        opt_workInProgress) {
+        opt_workInProgress, opt_baseChange) {
       return this.send('POST', '/changes/', {
         project,
         branch,
@@ -1413,6 +1435,7 @@
         topic: opt_topic,
         is_private: opt_isPrivate,
         work_in_progress: opt_workInProgress,
+        base_change: opt_baseChange,
       }).then(response => this.getResponseObject(response));
     },
 
@@ -1995,8 +2018,8 @@
           });
     },
 
-    getCapabilities(token) {
-      return this.fetchJSON('/config/server/capabilities');
+    getCapabilities(token, opt_errFn) {
+      return this.fetchJSON('/config/server/capabilities', opt_errFn);
     },
 
     setAssignee(changeNum, assignee) {
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
index 352f759..95a35e4 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser.js
index c119cdf..2451981 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function(window) {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser_test.html b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser_test.html
index bf082e8..202c52a 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/mock-diff-response_test.html b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/mock-diff-response_test.html
index add07ea..0a1b14e 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/mock-diff-response_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/mock-diff-response_test.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-select/gr-select.html b/polygerrit-ui/app/elements/shared/gr-select/gr-select.html
index ba945c4..e73d41c 100644
--- a/polygerrit-ui/app/elements/shared/gr-select/gr-select.html
+++ b/polygerrit-ui/app/elements/shared/gr-select/gr-select.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-select/gr-select.js b/polygerrit-ui/app/elements/shared/gr-select/gr-select.js
index 5e0cf30..b732fa5 100644
--- a/polygerrit-ui/app/elements/shared/gr-select/gr-select.js
+++ b/polygerrit-ui/app/elements/shared/gr-select/gr-select.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-select/gr-select_test.html b/polygerrit-ui/app/elements/shared/gr-select/gr-select_test.html
index 2bca29e..1748ec06 100644
--- a/polygerrit-ui/app/elements/shared/gr-select/gr-select_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-select/gr-select_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-storage/gr-storage.html b/polygerrit-ui/app/elements/shared/gr-storage/gr-storage.html
index 74bfcdf..6fc2f3f 100644
--- a/polygerrit-ui/app/elements/shared/gr-storage/gr-storage.html
+++ b/polygerrit-ui/app/elements/shared/gr-storage/gr-storage.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-storage/gr-storage.js b/polygerrit-ui/app/elements/shared/gr-storage/gr-storage.js
index dfe86c51..62080a1 100644
--- a/polygerrit-ui/app/elements/shared/gr-storage/gr-storage.js
+++ b/polygerrit-ui/app/elements/shared/gr-storage/gr-storage.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-storage/gr-storage_test.html b/polygerrit-ui/app/elements/shared/gr-storage/gr-storage_test.html
index 68d92cb..b7d73d4 100644
--- a/polygerrit-ui/app/elements/shared/gr-storage/gr-storage_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-storage/gr-storage_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.html b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.html
index 3c28674..e85fe38 100644
--- a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.html
+++ b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.js b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.js
index 519db55..c70dc8d 100644
--- a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.js
+++ b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.html b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.html
index 0434865..97f8ca4 100644
--- a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content.html b/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content.html
index 68db696..65f1fda 100644
--- a/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content.html
+++ b/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content.js b/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content.js
index 52f3ebd..c5de8f4 100644
--- a/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content.js
+++ b/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content_test.html b/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content_test.html
index 9b23a31..438d436 100644
--- a/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.html b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.html
index fa6c1e2..12a8f1c 100644
--- a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.html
+++ b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.js b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.js
index 62e70b5..fb87b558 100644
--- a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.js
+++ b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function() {
   'use strict';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip_test.html b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip_test.html
index 824fad5..3a47288 100644
--- a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/revision-info/revision-info.html b/polygerrit-ui/app/elements/shared/revision-info/revision-info.html
index 5669143..91f87d0 100644
--- a/polygerrit-ui/app/elements/shared/revision-info/revision-info.html
+++ b/polygerrit-ui/app/elements/shared/revision-info/revision-info.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/elements/shared/revision-info/revision-info_test.html b/polygerrit-ui/app/elements/shared/revision-info/revision-info_test.html
index 27233eb..433872d 100644
--- a/polygerrit-ui/app/elements/shared/revision-info/revision-info_test.html
+++ b/polygerrit-ui/app/elements/shared/revision-info/revision-info_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/embed/embed.html b/polygerrit-ui/app/embed/embed.html
index 14b6b66..f75fab8 100644
--- a/polygerrit-ui/app/embed/embed.html
+++ b/polygerrit-ui/app/embed/embed.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,6 +17,7 @@
 <link rel="import" href="../bower_components/polymer/polymer.html">
 <link rel="import" href="../elements/change/gr-change-view/gr-change-view.html">
 <link rel="import" href="../elements/diff/gr-diff-view/gr-diff-view.html">
-<link rel="import" href="../elements/change-list/gr-dashboard-view/gr-dashboard-view.html">
 <link rel="import" href="../elements/change-list/gr-change-list-view/gr-change-list-view.html">
+<link rel="import" href="../elements/change-list/gr-change-list/gr-change-list.html">
+<link rel="import" href="../elements/change-list/gr-dashboard-view/gr-dashboard-view.html">
 <link rel="import" href="../styles/app-theme.html">
diff --git a/polygerrit-ui/app/embed/embed_test.html b/polygerrit-ui/app/embed/embed_test.html
index 80f7e5d..88461d0 100644
--- a/polygerrit-ui/app/embed/embed_test.html
+++ b/polygerrit-ui/app/embed/embed_test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -48,6 +49,12 @@
   </template>
 </test-fixture>
 
+<test-fixture id="change-list">
+  <template>
+    <gr-change-list></gr-change-list>
+  </template>
+</test-fixture>
+
 <script>
   suite('embed test', () => {
     test('gr-change-view is embedded', () => {
@@ -69,5 +76,10 @@
       const element = fixture('change-list-view');
       assert.equal(element.is, 'gr-change-list-view');
     });
+
+    test('change-list is embedded', () => {
+      const element = fixture('change-list');
+      assert.equal(element.is, 'gr-change-list');
+    });
   });
 </script>
diff --git a/polygerrit-ui/app/embed/test.html b/polygerrit-ui/app/embed/test.html
index 0587562..eed2fef 100644
--- a/polygerrit-ui/app/embed/test.html
+++ b/polygerrit-ui/app/embed/test.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/index.html b/polygerrit-ui/app/index.html
index 080c345..242c04b 100644
--- a/polygerrit-ui/app/index.html
+++ b/polygerrit-ui/app/index.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/scripts/hiddenscroll.js b/polygerrit-ui/app/scripts/hiddenscroll.js
index b80742a..c62e6fc 100644
--- a/polygerrit-ui/app/scripts/hiddenscroll.js
+++ b/polygerrit-ui/app/scripts/hiddenscroll.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 
 (function(window) {
   window.Gerrit = window.Gerrit || {};
diff --git a/polygerrit-ui/app/scripts/rootElement.js b/polygerrit-ui/app/scripts/rootElement.js
index 1a07edf..619a7b1 100644
--- a/polygerrit-ui/app/scripts/rootElement.js
+++ b/polygerrit-ui/app/scripts/rootElement.js
@@ -1,20 +1,23 @@
-// Copyright (C) 2017 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.
+/**
+ * @license
+ * Copyright (C) 2017 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.
+ */
 
 (function(window) {
   window.Gerrit = window.Gerrit || {};
   if (window.Gerrit.hasOwnProperty('getRootElement')) { return; }
 
   window.Gerrit.getRootElement = () => document.body;
-})(window);
\ No newline at end of file
+})(window);
diff --git a/polygerrit-ui/app/scripts/util.js b/polygerrit-ui/app/scripts/util.js
index 573335c..b4ab21a 100644
--- a/polygerrit-ui/app/scripts/util.js
+++ b/polygerrit-ui/app/scripts/util.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+/**
+ * @license
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 (function(window) {
   'use strict';
 
diff --git a/polygerrit-ui/app/styles/app-theme.html b/polygerrit-ui/app/styles/app-theme.html
index e8db312..61142cb 100644
--- a/polygerrit-ui/app/styles/app-theme.html
+++ b/polygerrit-ui/app/styles/app-theme.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/styles/gr-change-list-styles.html b/polygerrit-ui/app/styles/gr-change-list-styles.html
index 7ba4fc6..76a8c1b 100644
--- a/polygerrit-ui/app/styles/gr-change-list-styles.html
+++ b/polygerrit-ui/app/styles/gr-change-list-styles.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/styles/gr-form-styles.html b/polygerrit-ui/app/styles/gr-form-styles.html
index 559e4f4..0417e91 100644
--- a/polygerrit-ui/app/styles/gr-form-styles.html
+++ b/polygerrit-ui/app/styles/gr-form-styles.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/styles/gr-menu-page-styles.html b/polygerrit-ui/app/styles/gr-menu-page-styles.html
index 81d4179..bafcbc6 100644
--- a/polygerrit-ui/app/styles/gr-menu-page-styles.html
+++ b/polygerrit-ui/app/styles/gr-menu-page-styles.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2016 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/styles/gr-page-nav-styles.html b/polygerrit-ui/app/styles/gr-page-nav-styles.html
index 0c4d20f..8d8659e 100644
--- a/polygerrit-ui/app/styles/gr-page-nav-styles.html
+++ b/polygerrit-ui/app/styles/gr-page-nav-styles.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/styles/gr-table-styles.html b/polygerrit-ui/app/styles/gr-table-styles.html
index f401d37..7b4d856 100644
--- a/polygerrit-ui/app/styles/gr-table-styles.html
+++ b/polygerrit-ui/app/styles/gr-table-styles.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/styles/gr-voting-styles.html b/polygerrit-ui/app/styles/gr-voting-styles.html
index d6ff0eb..9413851 100644
--- a/polygerrit-ui/app/styles/gr-voting-styles.html
+++ b/polygerrit-ui/app/styles/gr-voting-styles.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/styles/shared-styles.html b/polygerrit-ui/app/styles/shared-styles.html
index 7f7b441..80b01ce 100644
--- a/polygerrit-ui/app/styles/shared-styles.html
+++ b/polygerrit-ui/app/styles/shared-styles.html
@@ -1,4 +1,5 @@
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/test/common-test-setup.html b/polygerrit-ui/app/test/common-test-setup.html
index d901bec..246e7b8 100644
--- a/polygerrit-ui/app/test/common-test-setup.html
+++ b/polygerrit-ui/app/test/common-test-setup.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/polygerrit-ui/app/test/index.html b/polygerrit-ui/app/test/index.html
index 2bb8b2e..b5e3608 100644
--- a/polygerrit-ui/app/test/index.html
+++ b/polygerrit-ui/app/test/index.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2015 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
@@ -73,6 +74,7 @@
     'change/gr-download-dialog/gr-download-dialog_test.html',
     'change/gr-file-list-header/gr-file-list-header_test.html',
     'change/gr-file-list/gr-file-list_test.html',
+    'change/gr-included-in-dialog/gr-included-in-dialog_test.html',
     'change/gr-label-score-row/gr-label-score-row_test.html',
     'change/gr-label-scores/gr-label-scores_test.html',
     'change/gr-message/gr-message_test.html',
diff --git a/polygerrit-ui/app/test/test-router.html b/polygerrit-ui/app/test/test-router.html
index d96040f5..34ff374 100644
--- a/polygerrit-ui/app/test/test-router.html
+++ b/polygerrit-ui/app/test/test-router.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <!--
+@license
 Copyright (C) 2017 The Android Open Source Project
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/resources/com/google/gerrit/server/mail/ChangeFooterHtml.soy b/resources/com/google/gerrit/server/mail/ChangeFooterHtml.soy
index 99263e8..f802366 100644
--- a/resources/com/google/gerrit/server/mail/ChangeFooterHtml.soy
+++ b/resources/com/google/gerrit/server/mail/ChangeFooterHtml.soy
@@ -38,7 +38,7 @@
   {if $email.changeUrl}
     <div itemscope itemtype="http://schema.org/EmailMessage">
       <div itemscope itemprop="action" itemtype="http://schema.org/ViewAction">
-        <link itemprop="url" href="{$email.changeUrl}"/>
+        <link itemprop="url" href="{$email.changeUrl |blessStringAsTrustedResourceUrlForLegacy}"/>
         <meta itemprop="name" content="View Change"/>
       </div>
     </div>
diff --git a/resources/com/google/gerrit/server/mail/ChangeSubject.soy b/resources/com/google/gerrit/server/mail/ChangeSubject.soy
index d8cffc4..62092ae 100644
--- a/resources/com/google/gerrit/server/mail/ChangeSubject.soy
+++ b/resources/com/google/gerrit/server/mail/ChangeSubject.soy
@@ -22,7 +22,13 @@
  * @param branch
  * @param change
  * @param shortProjectName
+ * @param instanceAndProjectName
+ * @param addInstanceNameInSubject boolean
  */
 {template .ChangeSubject kind="text"}
-  Change in {$shortProjectName}[{$branch.shortName}]: {$change.shortSubject}
+  {if $addInstanceNameInSubject}
+    Change in {$shortProjectName}[{$branch.shortName}]: {$change.shortSubject}
+  {else}
+    Change in {$instanceAndProjectName}[{$branch.shortName}]: {$change.shortSubject}
+  {/if}
 {/template}
diff --git a/tools/bzl/license.bzl b/tools/bzl/license.bzl
index 3578173..38dfbe5 100644
--- a/tools/bzl/license.bzl
+++ b/tools/bzl/license.bzl
@@ -25,7 +25,7 @@
   # post process the XML into our favorite format.
   native.genrule(
     name = "gen_license_txt_" + name,
-    cmd = "python2 $(location //tools/bzl:license-map.py) %s %s > $@" % (" ".join(opts), " ".join(xmls)),
+    cmd = "python $(location //tools/bzl:license-map.py) %s %s > $@" % (" ".join(opts), " ".join(xmls)),
     outs = [ name + ".txt" ],
     tools = tools,
     **kwargs