Merge "Plugin support for project weblinks"
diff --git a/.buckversion b/.buckversion
index ea13b51..cec726d 100644
--- a/.buckversion
+++ b/.buckversion
@@ -1 +1 @@
-ca48f0fff22f7fbcb856fd2faa6e15e7de900775
+1ba4496a782b40dec33a42e69a74837afee06177
diff --git a/.gitignore b/.gitignore
index efff6da..9cfedb7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,3 +16,4 @@
 /local.properties
 *.pyc
 /gwt-unitCache
+*.swp
diff --git a/Documentation/access-control.txt b/Documentation/access-control.txt
index 79b44f7..8b2fd64 100644
--- a/Documentation/access-control.txt
+++ b/Documentation/access-control.txt
@@ -6,9 +6,10 @@
 users.
 
 
+[[system_groups]]
 == System Groups
 
-Gerrit comes with following system groups:
+Gerrit comes with the following system groups:
 
 * Administrators
 * Anonymous Users
@@ -375,6 +376,7 @@
 These are references with added functionality to them compared to a regular
 git push operation.
 
+[[refs_for]]
 ==== refs/for/<branch ref>
 
 Most prominent is the `refs/for/<branch ref>` reference which is the reference
@@ -818,6 +820,7 @@
 edited on open changes.
 
 
+[[example_roles]]
 == Examples of typical roles in a project
 
 Below follows a set of typical roles on a server and which access
diff --git a/Documentation/cmd-create-project.txt b/Documentation/cmd-create-project.txt
index b66f18a..b665f9c 100644
--- a/Documentation/cmd-create-project.txt
+++ b/Documentation/cmd-create-project.txt
@@ -113,7 +113,7 @@
 link:config-gerrit.html#repository.name.defaultSubmitType[
 repository.<name>.defaultSubmitType] is set to a different value.
 For more details see link:project-setup.html#submit_type[
-Change Submit Actions].
+Submit Types].
 
 --use-content-merge::
 	If enabled, Gerrit will try to perform a 3-way merge of text
diff --git a/Documentation/cmd-set-project.txt b/Documentation/cmd-set-project.txt
index c568e9c..adfc364 100644
--- a/Documentation/cmd-set-project.txt
+++ b/Documentation/cmd-set-project.txt
@@ -57,7 +57,7 @@
 
 +
 For more details see
-link:project-setup.html#submit_type[Change Submit Actions].
+link:project-setup.html#submit_type[Submit Types].
 
 --content-merge::
     If enabled, Gerrit will try to perform a 3-way merge of text
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index fa207d3..0b7eaeb 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -422,13 +422,16 @@
 [[auth.gitBasicAuth]]auth.gitBasicAuth::
 +
 If true then Git over HTTP and HTTP/S traffic is authenticated using
-standard BasicAuth and credentials validated against the randomly
-generated HTTP password or against LDAP when it is configured as
-Gerrit Web UI authentication method.
+standard BasicAuth and the credentials are validated using the same
+auth method as configured for the Gerrit Web UI.
 +
-This parameter only affects git over http traffic. If set to false
-then Gerrit will authenticate through DIGEST authentication and
-the randomly generated HTTP password in Gerrit DB.
+This parameter affects git over HTTP traffic and access to the REST
+API. If set to false then Gerrit will authenticate through DIGEST
+authentication and the randomly generated HTTP password in the Gerrit
+database.
++
+When `auth.type` is `LDAP`, service users that only exist in the Gerrit
+database are still authenticated by their HTTP passwords.
 +
 By default this is set to false.
 
@@ -1906,6 +1909,12 @@
 If the file doesn't exist or can't be read the default robots.txt file
 bundled with the .war will be used instead.
 
+[[httpd.registerMBeans]]httpd.registerMBeans::
++
+Enable (or disable) registration of Jetty MBeans for Java JMX.
++
+By default, false.
+
 [[index]]
 === Section index
 
diff --git a/Documentation/config-hooks.txt b/Documentation/config-hooks.txt
index 0f4d094..4635f80 100644
--- a/Documentation/config-hooks.txt
+++ b/Documentation/config-hooks.txt
@@ -41,7 +41,7 @@
 changes and drafts).
 
 ====
-  patchset-created --change <change id> --is-draft <boolean> --change-url <change url> --project <project name> --branch <branch> --topic <topic> --uploader <uploader> --commit <sha1> --patchset <patchset id>
+  patchset-created --change <change id> --is-draft <boolean> --change-url <change url> --change-owner <change owner> --project <project name> --branch <branch> --topic <topic> --uploader <uploader> --commit <sha1> --patchset <patchset id>
 ====
 
 === draft-published
@@ -49,7 +49,7 @@
 This is called whenever a draft change is published.
 
 ====
-  draft-published --change <change id> --change-url <change url> --project <project name> --branch <branch> --topic <topic> --uploader <uploader> --commit <sha1> --patchset <patchset id>
+  draft-published --change <change id> --change-url <change url> --change-owner <change owner> --project <project name> --branch <branch> --topic <topic> --uploader <uploader> --commit <sha1> --patchset <patchset id>
 ====
 
 === comment-added
@@ -57,7 +57,7 @@
 This is called whenever a comment is added to a change.
 
 ====
-  comment-added --change <change id> --is-draft <boolean> --change-url <change url> --project <project name> --branch <branch> --topic <topic> --author <comment author> --commit <commit> --comment <comment> [--<approval category id> <score> --<approval category id> <score> ...]
+  comment-added --change <change id> --is-draft <boolean> --change-url <change url> --change-owner <change owner> --project <project name> --branch <branch> --topic <topic> --author <comment author> --commit <commit> --comment <comment> [--<approval category id> <score> --<approval category id> <score> ...]
 ====
 
 === change-merged
@@ -65,7 +65,7 @@
 Called whenever a change has been merged.
 
 ====
-  change-merged --change <change id> --change-url <change url> --project <project name> --branch <branch> --topic <topic> --submitter <submitter> --commit <sha1>
+  change-merged --change <change id> --change-url <change url> --change-owner <change owner> --project <project name> --branch <branch> --topic <topic> --submitter <submitter> --commit <sha1>
 ====
 
 === merge-failed
@@ -73,7 +73,7 @@
 Called whenever a change has failed to merge.
 
 ====
-  merge-failed --change <change id> --change-url <change url> --project <project name> --branch <branch> --topic <topic> --submitter <submitter> --commit <sha1> --reason <reason>
+  merge-failed --change <change id> --change-url <change url> --change-owner <change owner> --project <project name> --branch <branch> --topic <topic> --submitter <submitter> --commit <sha1> --reason <reason>
 ====
 
 === change-abandoned
@@ -81,7 +81,7 @@
 Called whenever a change has been abandoned.
 
 ====
-  change-abandoned --change <change id> --change-url <change url> --project <project name> --branch <branch> --topic <topic> --abandoner <abandoner> --commit <sha1> --reason <reason>
+  change-abandoned --change <change id> --change-url <change url> --change-owner <change owner> --project <project name> --branch <branch> --topic <topic> --abandoner <abandoner> --commit <sha1> --reason <reason>
 ====
 
 === change-restored
@@ -89,7 +89,7 @@
 Called whenever a change has been restored.
 
 ====
-  change-restored --change <change id> --change-url <change url> --project <project name> --branch <branch> --topic <topic> --restorer <restorer> --commit <sha1> --reason <reason>
+  change-restored --change <change id> --change-url <change url> --change-owner <change owner> --project <project name> --branch <branch> --topic <topic> --restorer <restorer> --commit <sha1> --reason <reason>
 ====
 
 === ref-updated
@@ -105,7 +105,7 @@
 Called whenever a reviewer is added to a change.
 
 ====
-  reviewer-added --change <change id> --change-url <change url> --project <project name> --branch <branch> --reviewer <reviewer>
+  reviewer-added --change <change id> --change-url <change url> --change-owner <change owner> --project <project name> --branch <branch> --reviewer <reviewer>
 ====
 
 === topic-changed
@@ -113,7 +113,7 @@
 Called whenever a change's topic is changed from the Web UI or via the REST API.
 
 ====
-  topic-changed --change <change id> --project <project name> --branch <branch> --changer <changer> --old-topic <old topic> --new-topic <new topic>
+  topic-changed --change <change id> --change-owner <change owner> --project <project name> --branch <branch> --changer <changer> --old-topic <old topic> --new-topic <new topic>
 ====
 
 === cla-signed
diff --git a/Documentation/config-labels.txt b/Documentation/config-labels.txt
index fc25f22..0fe12ca 100644
--- a/Documentation/config-labels.txt
+++ b/Documentation/config-labels.txt
@@ -169,6 +169,20 @@
 optional leading `+`.
 
 
+[[label_defaultValue]]
+=== `label.Label-Name.defaultValue`
+
+The default value (or score) for the label.  The defaultValue must be
+within the range of valid label values.  It is an optional label setting,
+if not defined the defaultValue for the label will be 0.  When a
+defaultValue is defined, that value will get set in the Reply dialog
+by default.
+
+A defaultValue can be set to a score that is outside of the permissible
+range for a user.  In that case the score that will get set in the Reply
+box will be either the lowest or highest score in the permissible range.
+
+
 [[label_abbreviation]]
 === `label.Label-Name.abbreviation`
 
@@ -297,6 +311,32 @@
 copyright` will block submit, while `+1 Copyright clear` is required to
 enable submit.
 
+=== Default Value Example
+
+This example attempts to describe how a label default value works with the
+user permissions.  Assume the configuration below.
+
+====
+  [access "refs/heads/*"]
+      label-Snarky-Review = -3..+3 group Administrators
+      label-Snarky-Review = -2..+2 group Project Owners
+      label-Snarky-Review = -1..+1 group Registered Users
+  [label "Snarky-Review"]
+      value = -3 Ohh, hell no!
+      value = -2 Hmm, I'm not a fan
+      value = -1 I'm not sure I like this
+      value =  0 No score
+      value = +1 I like, but need another to like it as well
+      value = +2 Hmm, this is pretty nice
+      value = +3 Ohh, hell yes!
+      defaultValue = -3
+====
+
+Upon clicking the Reply button:
+* Administrators have all scores (-3..+3) available, -3 is set as the default.
+* Project Owners have limited scores (-2..+2) available, -2 is set as the default.
+* Registered Users have limited scores (-1..+1) available, -1 is set as the default.
+
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
diff --git a/Documentation/config-project-config.txt b/Documentation/config-project-config.txt
index 2fb256f..64fa9c4 100644
--- a/Documentation/config-project-config.txt
+++ b/Documentation/config-project-config.txt
@@ -171,6 +171,21 @@
 documentation for a full list of available access rights.
 
 
+[[mimetype-section]]
+=== MIME Types section
+
+The +mimetype+ section may be configured to force the web code
+reviewer to return certain MIME types by file path. MIME types
+may be used to activate syntax highlighting.
+
+----
+[mimetype "text/x-c"]
+  path = *.pkt
+[mimetype "text/x-java"]
+  path = api/current.txt
+----
+
+
 [[capability-section]]
 === Capability section
 
diff --git a/Documentation/dev-buck.txt b/Documentation/dev-buck.txt
index 33c4e9f..45bd6ec 100644
--- a/Documentation/dev-buck.txt
+++ b/Documentation/dev-buck.txt
@@ -283,6 +283,21 @@
   buck test --all --exclude slow
 ----
 
+To include a specific group of acceptance tests:
+
+----
+  buck test --all --include api
+----
+
+The following groups of tests are currently supported:
+
+* api
+* git
+* pgm
+* rest
+* server
+* ssh
+
 To run a specific test, e.g. the acceptance test
 `com.google.gerrit.acceptance.git.HttpPushForReviewIT`:
 
@@ -478,25 +493,17 @@
   EOF
 ----
 
-== Sporadic failures of unit tests
+== Rerun unit tests
 
-In case unit tests are failing for non obvious reasons, failed tests may need
-to be repeated:
-
-----
-FAIL  32,0s  7 Passed   1 Failed   com.google.gerrit.acceptance.rest.group.AddRemoveGroupMembersIT
-FAILURE includeRemoveGroup: verify: false
-com.jcraft.jsch.JSchException: verify: false
-----
-
-Because the test execution results are cached by Buck, they must be removed
-before retrying:
+If for some reasons tests, that were already run must be repeated, unit test
+cache must be removed fist. That's because the test execution results are
+cached by Buck:
 
 ----
   $ rm -rf buck-out/bin/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/.AddRemoveGroupMembersIT/
 ----
 
-After clearing the cache and repeating of the failed tests, they are successful:
+After clearing the cache test can be rerun again:
 
 ----
   $ buck test //gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group:AddRemoveGroupMembersIT
@@ -516,6 +523,14 @@
 ----
 
 When this option is used, cache is disabled per design and doesn't need to be deleted.
+Note: when -f option is used, the whole unit test cache is dropped. As a consequence,
+repeating the
+
+----
+buck test --all
+----
+
+would re-execute all tests again.
 
 GERRIT
 ------
diff --git a/Documentation/dev-plugins.txt b/Documentation/dev-plugins.txt
index 73f4bab..ec98a91 100644
--- a/Documentation/dev-plugins.txt
+++ b/Documentation/dev-plugins.txt
@@ -36,7 +36,7 @@
 ----
 mvn archetype:generate -DarchetypeGroupId=com.google.gerrit \
     -DarchetypeArtifactId=gerrit-plugin-archetype \
-    -DarchetypeVersion=2.9-SNAPSHOT \
+    -DarchetypeVersion=2.10-SNAPSHOT \
     -DgroupId=com.googlesource.gerrit.plugins.testplugin \
     -DartifactId=testplugin
 ----
@@ -1577,10 +1577,11 @@
 <inherits name="com.google.gwt.json.JSON"/>
 ----
 
+[[screen]]
 == Add Screen
-A GWT plugin can add a menu item that opens a screen that is
-implemented by the plugin. This way plugin screens can be fully
-integrated into the Gerrit UI.
+A link:#gwt_ui_extension[GWT plugin] can link:#top-menu-extensions[add
+a menu item] that opens a screen that is implemented by the plugin.
+This way plugin screens can be fully integrated into the Gerrit UI.
 
 Example menu item:
 [source,java]
diff --git a/Documentation/dev-readme.txt b/Documentation/dev-readme.txt
index 83d8f1a..da1ca70 100644
--- a/Documentation/dev-readme.txt
+++ b/Documentation/dev-readme.txt
@@ -50,6 +50,13 @@
 refer to: link:dev-buck.html#eclipse[Eclipse integration with Buck].
 
 
+== Configuring IntelliJ IDEA
+
+To use IntelliJ IDEA for development, the easiest way is to follow
+Eclipse integration and then open it as Eclipse project in IDEA.
+You need the Eclipse plugin activated in IntelliJ IDEA.
+
+
 == Mac OS X
 
 On Mac OS X ensure "Java For Mac OS X 10.5 Update 4" (or later) has
diff --git a/Documentation/index.txt b/Documentation/index.txt
index 131e81d..33f1e95 100644
--- a/Documentation/index.txt
+++ b/Documentation/index.txt
@@ -4,6 +4,7 @@
 . Getting started
 .. link:intro-quick.html[A Quick Introduction to Gerrit]
 .. link:intro-change-screen.html[A Quick Introduction to the New Change Screen]
+.. link:intro-project-owner.html[Project Owner Guide]
 .. link:http://source.android.com/submit-patches/workflow[Default Android Workflow] (external)
 . Web
 .. Registering a new Gerrit account
diff --git a/Documentation/install-j2ee.txt b/Documentation/install-j2ee.txt
index 50eccc2..4f438e5 100644
--- a/Documentation/install-j2ee.txt
+++ b/Documentation/install-j2ee.txt
@@ -109,6 +109,21 @@
 `system_config`) is as simple as touching the context config file:
 `'$JETTY_HOME'/contexts/gerrit.xml`
 
+== Tomcat 7.x
+
+[TIP]
+If reverse proxy is used in front of Tomcat then see the configuration
+instructions for encoding slashes link:config-reverseproxy.html. Otherwise
+Tomcat must be configured to encode slashes, by adding
+-Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true to
+CATALINA_OPTS environment variable. Excerpt from the documentation
+https://tomcat.apache.org/tomcat-7.0-doc/config/systemprops.html:
+
+----
+Property org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH:
+If this is true '%2F' and '%5C' will be permitted as path delimiters.
+If not specified, the default value of false will be used.
+----
 
 GERRIT
 ------
diff --git a/Documentation/intro-project-owner.txt b/Documentation/intro-project-owner.txt
new file mode 100644
index 0000000..23e7e0b
--- /dev/null
+++ b/Documentation/intro-project-owner.txt
@@ -0,0 +1,742 @@
+= Project Owner Guide
+
+This is a Gerrit guide that is dedicated to project owners. It
+explains the many possibilities that Gerrit provides to customize the
+workflows for a project.
+
+[[project-owner]]
+== What is a project owner?
+
+Being project owner means that you own a project in Gerrit.
+Technically this is expressed by having the
+link:access-control.html#category_owner[Owner] access right on
+`refs/*` on that project. As project owner you have the permission to
+edit the access control list and the project settings of the project.
+It also means that you should get familiar with these settings so that
+you can adapt them to the needs of your project.
+
+Being project owner means being responsible for the administration of
+a project. This requires having a deeper knowledge of Gerrit than the
+average user. Normally per team there should be 2 to 3 persons, who
+have a certain level of Git/Gerrit knowledge, assigned as project
+owners. It normally doesn't make sense that everyone in a team is
+project owner. For normal team members it is sufficient to be committer
+or contributor.
+
+[[access-rights]]
+== Access Rights
+
+As a project owner you can edit the access control list of your
+project. This allows you to grant permissions on the project to
+different groups.
+
+Gerrit comes with a rich set of permissions which allow a very
+fine-grained control over who can do what on a project. Access
+control is one of the most powerful Gerrit features but it is also a
+rather complex topic. This guide will only highlight the most
+important aspects of access control, but the link:access-control.html[
+Access Control] chapter explains all the details.
+
+[[edit-access-rights]]
+=== Editing Access Rights
+
+To see the access rights of your project
+
+- go to the Gerrit WebUI
+- click on the `Projects` > `List` menu entry
+- find your project in the project list and click on it
+- click on the `Access` menu entry
+
+By clicking on the `Edit` button the access rights become editable and
+you may save any changes by clicking on the `Save Changes` button.
+Optionally you can provide a `Commit Message` to explain the reasons
+for changing the access rights.
+
+The access rights are stored in the project's Git repository in a
+special branch called `refs/meta/config`. On this branch there is a
+`project.config` file which contains the access rights. More
+information about this storage format can be found in the
+link:config-project-config.html[Project Configuration File Format]
+chapter. What is important to know is that by looking at the history
+of the `project.config` file on the `refs/meta/config` branch you can
+always see how the access rights were changed and by whom. If a good
+commit message is provided you can also see from the history why the
+access rights were modified.
+
+If a Git browser such as GitWeb is configured for the Gerrit server you
+can find a link to the history of the `project.config` file in the
+WebUI. Otherwise you may inspect the history locally. If you have
+cloned the repository you can do this by executing the following
+commands:
+
+====
+  $ git fetch origin refs/meta/config:config
+  $ git checkout config
+  $ git log project.config
+====
+
+Non project owners may still edit the access rights and propose the
+modifications to the project owners by clicking on the `Save for
+Review` button. This creates a new change with the access rights
+modifications that can be approved by a project owner. The project
+owners are automatically added as reviewer on this change so that they
+get informed about it by email.
+
+[[inheritance]]
+=== Inheritance
+
+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
+project can have only a single parent project, multi-inheritance is
+not supported.
+
+Looking at the access rights of your project in the Gerrit WebUI, you
+only see the access rights which are defined on that project. To see
+the inherited access rights you must follow the link to the parent
+project under `Rights Inherit From`.
+
+Inherited access rights can be overwritten unless they are defined as
+link:access-control.html#block[BLOCK rule]. BLOCK rules are used to
+limit the possibilities of the project owners on the inheriting
+projects. With this, global policies can be enforced on all projects.
+Please note that Gerrit doesn't prevent you from assigning access
+rights that contradict an inherited BLOCK rule, but these access rights
+will simply have no effect.
+
+If you are responsible for several projects which require the same
+permissions, it makes sense to have a common parent for them and to
+maintain the access rights on that common parent. Changing the parent
+of a project is only allowed for Gerrit administrators. This means you
+need to contact the administrator of your Gerrit server if you want to
+reparent your project. One way to do this is to change the parent
+project in the WebUI, save the modifications for review and get the
+change approved and merged by a Gerrit administrator.
+
+[[refs]]
+=== References
+
+Access rights in Gerrit are assigned on references (aka refs). Refs in
+Git exist in different namespaces, e.g. all branches normally exist
+under `refs/heads/` and all tags under `refs/tags/`. In addition there
+are a number of link:access-control.html#references_special[special refs]
+and link:access-control.html#references_magic[magic refs].
+
+Access rights can be assigned on a concrete ref, e.g.
+`refs/heads/master` but also on ref patterns and regular expressions
+for ref names.
+
+A ref pattern ends with `/*` and describes a complete ref name
+namespace, e.g. access rights assigned on `refs/heads/*` apply to all
+branches.
+
+Regular expressions must start with `^`, e.g. access rights assigned
+on `^refs/heads/rel-.*` would apply to all `rel-*` branches.
+
+[[groups]]
+=== Groups
+
+Access rights are granted to groups. It is useful to know that Gerrit
+maintains its own groups internally but also supports different external
+group backends.
+
+The Gerrit internal groups can be seen in the Gerrit WebUI by clicking
+on the `Groups` > `List` menu entry. By clicking on a group you can
+edit the group members (`Members` tab) and the group options
+(`General` tab).
+
+Gerrit internal groups contain users as members, but can also include
+other groups, even external groups.
+
+Every group is owned by an owner group. Only members of the owner
+group can administrate the owned group (assign members, edit the group
+options). A group can own itself; in this case members of the group
+can, for example, add further members to the group. When you create new
+groups for your project to assign access rights to committer or other
+roles, make sure that they are owned by the project owner group.
+
+An important setting on a group is the option
+`Make group visible to all registered users.`, which defines whether
+non-members can see who is member of the group.
+
+New internal Gerrit groups can be created under `Groups` >
+`Create New Group`. This menu is only available if you have the global
+capability link:access-control.html#capability_createGroup[Create Group]
+assigned.
+
+Gerrit also has a set of special
+link:access-control.html#system_groups[system groups] that you might
+find useful.
+
+External groups need to be prefixed when assigning access rights to
+them, e.g. link:access-control.html#ldap_groups[LDAP group names] need
+to be prefixed with `ldap/`.
+
+If the link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/singleusergroup[
+singleusergroup] plugin is installed you can also directly assign
+access rights to users, by prefixing the username with `user/` or the
+user's account ID by `userid/`.
+
+[[common-access-rights]]
+=== Common Access Rights
+
+Different roles in a project, such as developer (committer) or
+contributor, need different access rights. Examples for which access
+rights are typically assigned for which role are described in the
+link:access-control.html#example_roles[Access Control] chapter.
+
+[[code-review]]
+=== Code Review
+
+Gerrit's main functionality is code review, however using code review
+is optional and you may decide to only use Gerrit as a Git server with
+access control. Whether you allow only pushes for review or also
+direct pushes depends on the project's access rights.
+
+To push a commit for review it must be pushed to
+link:access-control.html#refs_for[refs/for/<branch-name>]. This means
+the link:access-control.html#category_push_review[Push] access right
+must be assigned on `refs/for/<branch-name>`.
+
+To allow direct pushes and bypass code review, the
+link:access-control.html#category_push_direct[Push] access right is
+required on `refs/heads/<branch-name>`.
+
+By pushing for review you are not only enabling the review workflow,
+but you can also get link:#continuous-integration[automatic
+verifications from a build server] before changes are merged. In
+addition you can benefit from Gerrit's merge strategies that can
+automatically merge/rebase commits on server side if necessary. You can
+control the merge strategy by configuring the
+link:project-setup.html#submit_type[submit type] on the project. If you
+bypass code review you always need to merge/rebase manually if the tip
+of the destination branch has moved. Please keep this in mind if you
+choose to not work with code review because you think it's easier to
+avoid the additional complexity of the review workflow; it might
+actually not be easier.
+
+You may also enable link:user-upload.html#auto_merge[auto-merge on
+push] to benefit from the automatic merge/rebase on server side while
+pushing directly into the repository.
+
+[[project-options]]
+== Project Options
+
+As project owner you can control several options on your project.
+The different options are described in the
+link:project-setup.html#project_options[Project Options] section.
+
+To see the options of your project
+
+- go to the Gerrit WebUI
+- click on the `Projects` > `List` menu entry
+- find your project in the project list and click on it
+- click on the `General` menu entry
+
+[[submit-type]]
+=== Submit Type
+
+An important decision for a project is the choice of the submit type
+and the content merge setting (aka `Automatically resolve conflicts`).
+The link:project-setup.html#submit_type[submit type] is the method
+Gerrit uses to submit a change to the project. The submit type defines
+what Gerrit should do on submit of a change if the destination branch
+has moved while the change was in review. The
+link:project-setup.html#content_merge[content merge] setting applies
+if the same files have been modified concurrently and tells Gerrit
+whether it should attempt a content merge for these files.
+
+When choosing the submit type and the content merge setting one must
+weigh development comfort against the safety of not breaking the
+destination branch.
+
+The most restrictive submit type is
+link:project-setup.html#fast_forward_only[Fast Forward Only]. Using
+this submit type means that after submitting one change all other open
+changes for the same destination branch must be rebased manually. This
+is quite burdensome and in practice only feasible for branches with
+very few changes. On the other hand, if changes are verified before
+submit, e.g. automatically by a CI integration, with this submit type,
+you can be sure that the destination branch never gets broken.
+
+Choosing link:project-setup.html#merge_if_necessary[Merge If Necessary]
+as submit type makes the life for developers more comfortable,
+especially if content merge is enabled. If this submit strategy is used
+developers only need to rebase manually if the same files have been
+modified concurrently or if the content merge on such a file fails. The
+drawback with this submit type is that there is a risk of breaking
+the destination branch, e.g. if one change moves a class into another
+package and another change imports this class from the old location.
+Experience shows that in practice `Merge If Necessary` with content
+merge enabled works pretty well and breaking the destination branch
+happens rarely. This is why this setting is recommended at least for
+development branches. You likely want to start with
+`Merge If Necessary` with content merge enabled and only switch to a
+more restrictive policy if you are facing issues with the build and
+test stability of the destination branches.
+
+It is also possible to define the submit type dynamically via
+link:#prolog-submit-type[Prolog]. This way you can use different submit
+types for different branches.
+
+Please note that there are other submit types available; they are
+described in the link:project-setup.html#submit_type[Submit Type]
+section.
+
+[[labels]]
+== Labels
+
+The code review process includes that reviewers formally express their
+opinion about a change by voting on different link:config-labels.html[
+labels]. By default Gerrit comes with the
+link:config-labels.html#label_Code-Review[Code-Review] label and many
+Gerrit servers have the link:config-labels.html#label_Verified[Verified]
+label configured globally. However projects can also define their own
+link:config-labels.html#label_custom[custom labels] to formalize
+project-specific workflows. For example if a project requires an IP
+approval from a special IP-team, it can define an `IP-Review` label
+and grant permissions to the IP-team to vote on this label.
+
+The behavior of a label can be controlled by its
+link:config-labels.html#label_function[function], e.g. it can be
+configured whether a max positive voting on the label is required for
+submit or if the voting on the label is optional.
+
+By using a custom link:#submit-rules[submit rule] it can be controlled
+per change whether a label is required for submit or not.
+
+A useful feature on labels is the possibility to automatically copy
+scores forward to new patch sets if it was a
+link:config-labels.html#label_copyAllScoresOnTrivialRebase[trivial
+rebase] or if link:config-labels.html#label_copyAllScoresIfNoCodeChange[
+there was no code change] (e.g. only the commit message was edited).
+
+[[submit-rules]]
+== Submit Rules
+
+A link:prolog-cookbook.html#SubmitRule[submit rule] in Gerrit is logic
+that defines when a change is submittable. By default, a change is
+submittable when it gets at least one highest vote on each label and
+has no lowest vote (aka veto vote) on any label.
+
+The submit rules in Gerrit are implemented in link:prolog-cookbook.html[
+Prolog] and projects that need more flexibility can define their own
+submit rules to decide when a change should be submittable. A good
+link:prolog-cookbook.html#NonAuthorCodeReview[example] from the Prolog
+cookbook shows how to allow submit only if a change has a
+`Code-Review+2` vote from a person that is not the change author. This
+way a four-eyes principle for the reviews can be enforced.
+
+A Prolog submit rule has access to link:prolog-change-facts.html[
+information] about the change for which it is testing the
+submittability. Amongst others the list of the modified files can be
+accessed, which allows special logic if certain files are touched. For
+example, a common practice is to require a vote on an additional label,
+like `Library-Compliance`, if the dependencies of the project are
+changed.
+
+[[prolog-submit-type]]
+It is also possible to control the link:prolog-cookbook.html#SubmitType[
+submit type] from Prolog. For example this can be used to define a more
+restrictive submit type such as `Fast Forward Only` for stable branches
+while using a more liberal submit type, e.g. `Merge If Necessary` with
+content merge, for development branches. How this can be done can be
+seen from an link:prolog-cookbook.html#SubmitTypePerBranch[example] in
+the Prolog cookbook.
+
+Submit rules are maintained in the link:prolog-cookbook.html#RulesFile[
+rules.pl] file in the `refs/meta/config` branch of the project. How to
+write submit rules is explained in the
+link:prolog-cookbook.html#HowToWriteSubmitRules[Prolog cookbook]. There
+is also good support for link:prolog-cookbook.html#TestingSubmitRules[
+testing submit rules] while developing them.
+
+[[continuous-integration]]
+== Continuous Integration
+
+With Gerrit you can have continuous integration builds not only for
+updates of central branches but also whenever a new change/patch set is
+uploaded for review. This way you get automatic verification of all
+changes *before* they are merged and any build and test issues are
+detected early. To indicate the build and test status the continuous
+integration system normally votes with the
+link:config-labels.html#label_Verified[Verified] label on the change.
+
+There are several solutions for integrating continuous integration
+systems. The most commonly used are:
+
+- link:https://wiki.jenkins-ci.org/display/JENKINS/Gerrit+Trigger[
+  Gerrit Trigger] plugin for link:http://jenkins-ci.org/[Jenkins]
+
+- link:http://www.mediawiki.org/wiki/Continuous_integration/Zuul[
+  Zuul] for link:http://jenkins-ci.org/[Jenkins]
+
+For the integration with the continuous integration system you must
+have a service user that is able to access Gerrit. To create a service
+user in Gerrit you can use the link:cmd-create-account.html[create-account]
+SSH command if the link:access-control.html#capability_createAccount[
+Create Account] global capability is granted. If not, you need to ask
+a Gerrit administrator to create the service user.
+
+If the link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/serviceuser[
+serviceuser] plugin is installed you can also create new service users
+in the Gerrit WebUI under `People` > `Create Service User`. For this
+the `Create Service User` global capability must be assigned.
+
+The service user must have link:access-control.html#category_read[read]
+access to your project. In addition, if automatic change verification
+is enabled, the service user must be allowed to vote on the
+link:config-labels.html#label_Verified[Verified] label.
+
+Continuous integration systems usually integrate with Gerrit by
+listening to the Gerrit link:cmd-stream-events.html#events[stream
+events]. For this the service user must have the
+link:access-control.html#capability_streamEvents[Stream Events] global
+capability assigned.
+
+[[branch-administration]]
+== Branch Administration
+
+As project owner you can administrate the branches of your project in
+the Gerrit WebUI under `Projects` > `List` > <your project> >
+`Branches`. In the WebUI both link:project-setup.html#branch-creation[
+branch creation] and link:project-setup.html#branch-deletion[branch
+deletion] are allowed for project owners without requiring any
+additional access rights.
+
+By setting `HEAD` on the project you can define its
+link:project-setup.html#default-branch[default branch]. For convenience
+reasons, when the repository is cloned Git creates a local branch for
+this default branch and checks it out.
+
+[[notifications]]
+== Email Notifications
+
+With Gerrit individual users control their own email subscriptions. By
+editing the link:user-notify.html#user[watched projects] in the WebUI
+under `Settings` > `Watched Projects` users can decide which events to
+be informed about by email. The change notifications can be filtered by
+link:user-search.html[change search expressions].
+
+This means as a project owner you normally don't need to do anything
+about email notifications, except maybe telling your project team where
+to configure the watches.
+
+Gerrit also supports link:user-notify.html#project[notifications on
+project level] that allow project owners to set up email notifications
+for team mailing lists or groups of users. This configuration is done
+in the `project.config` file in the `refs/meta/config` branch as
+explained in the section about link:user-notify.html#project[project
+level notifications].
+
+[[dashboards]]
+== Dashboards
+
+Gerrit comes with a pre-defined user dashboard that provides a view
+of the changes that are relevant for a user. Users can also define
+their own link:user-dashboards.html[custom dashboards] where the
+dashboard sections can be freely configured. As a project owner you can
+configure such custom dashboards on
+link:user-dashboards.html#project-dashboards[project level]. This way
+you can define a view of the changes that are relevant for your
+project and share this dashboard with all users. The project dashboards
+can be seen in the WebUI under `Projects` > `List` > <your project> >
+`Dashboards`.
+
+[[issue-tracker-integration]]
+== Issue Tracker Integration
+
+There are several possibilities to integrate issue trackers with
+Gerrit.
+
+- Comment Links
++
+As described in the link#comment-links[Comment Links] section, comment
+links can be used to link IDs from commit message footers to issues in
+an issue tracker system.
+
+- Tracking IDs
++
+Gerrit can be configured to index IDs from commit message footers so
+that the link:user-search.html#tr[tr/bug] search operators can be used
+to query for changes with a certain ID. The
+link:config-gerrit.html#trackingid[configuration of tracking IDs] can
+only be done globally by a Gerrit administrator.
+
+- Issue Tracker System Plugins
++
+There are Gerrit plugins for a tight integration with
+link:https://gerrit-review.googlesource.com/\#/admin/projects/plugins/its-jira[Jira],
+link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/its-bugzilla[Bugzilla] and
+link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/its-rtc[IBM Rational Team Concert].
+If installed, these plugins can e.g. be used to automatically add links
+to Gerrit changes to the issues in the issue tracker system or to
+automatically close an issue if the corresponding change is merged.
+If installed, project owners may enable/disable the issue tracker
+integration from the Gerrit WebUI under `Projects` > `Lists` >
+<your project> > `General`.
+
+[[comment-links]]
+== Comment Links
+
+Gerrit can linkify strings in commit messages, summary comments and
+inline comments. A string that matches a defined regular expression is
+then displayed as hyperlink to a configured backend system.
+
+So called comment links can be configured globally by a Gerrit
+administrator, but also per project by the project owner. Comment links
+on project level are defined in the `project.config` file in the
+`refs/meta/config` branch of the project as described in the
+documentation of the link:config-gerrit.html#commentlink[commentlink]
+configuration parameter.
+
+Often comment links are used to link an ID in a commit message footer
+to an issue in an issue tracker system. For example, to link the ID
+from the `Bug` footer to Jira the following configuration can be used:
+
+====
+  [commentlink "myjira"]
+    match = ([Bb][Uu][Gg]:\\s+)(\\S+)
+    link =  https://myjira/browse/$2
+====
+
+[[reviewers]]
+== Reviewers
+
+Normally it is not needed to explicitly assign reviewers to every
+change since the project members either link:user-notify.html#user[
+watch the project] and get notified by email or regularly check the
+list of open changes in the Gerrit WebUI. The project members then
+pick the changes themselves that are interesting to them for review.
+
+If authors of changes want to have a review by a particular person
+(e.g. someone who is known to be expert in the touched code area, or a
+stakeholder for the implemented feature), they can request the review
+by adding this person in the Gerrit WebUI as a reviewer on the change.
+Gerrit will then notify this person by email about the review request.
+
+With the link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/reviewers[
+reviewers] plugin it is possible to configure default reviewers who
+will be automatically added to each change. The default reviewers can
+be configured in the Gerrit WebUI under `Projects` > `List` >
+<your project> > `General` in the `reviewers Plugin` section.
+
+The link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/reviewers-by-blame[
+reviewers-by-blame] plugin can automatically add reviewers to changes
+based on the link:https://www.kernel.org/pub/software/scm/git/docs/git-blame.html[
+git blame] computation on the changed files. This means that the plugin
+will add those users as reviewer that authored most of the lines
+touched by the change, since these users should be familiar with the
+code and can most likely review the change. How many reviewers the
+plugin will add to a change at most can be configured in the Gerrit
+WebUI under `Projects` > `List` > <your project> > `General` in the
+`reviewers-by-blame Plugin` section.
+
+[[download-commands]]
+== Download Commands
+
+On the change screen in the `Downloads` drop-down panel Gerrit offers
+commands for downloading the currently viewed patch set.
+
+The download commands are implemented by Gerrit plugins. This means
+that the available download commands depend on the installed Gerrit
+plugins:
+
+- link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/download-commands[
+  download-commands] plugin:
++
+The `download-commands` plugin provides the default download commands
+(`Checkout`, `Cherry Pick`, `Format Patch` and `Pull`).
++
+Gerrit administrators may configure which of the commands are shown on
+the change screen.
+
+- link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/egit[
+  egit] plugin:
++
+The `egit` plugin provides the change ref as a download command, which is
+needed for downloading a change from within
+link:https://www.eclipse.org/egit/[EGit].
+
+- link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/project-download-commands[
+  project-download-commands] plugin:
++
+The `project-download-commands` plugin enables project owners to
+configure project-specific download commands. For example, a
+project-specific download command may update submodules, trigger a
+build, execute the tests or even do a deployment.
++
+The project-specific download commands must be configured in the
+`project.config` file in the `refs/meta/config` branch of the project:
++
+====
+  [plugin "project-download-commands"]
+    Build = git fetch ${url} ${ref} && git checkout FETCH_HEAD && buck build ${project}
+    Update = git fetch ${url} ${ref} && git checkout FETCH_HEAD && git submodule update
+====
++
+Project-specific download commands that are defined on a parent project
+are inherited by the child projects. A child project can overwrite an
+inherited download command, or remove it by assigning no value to it.
+
+[[theme]]
+== Theme
+
+Gerrit supports project-specific themes for customizing the appearance
+of the change screen and the diff screens. It is possible to define an
+HTML header and footer and to adapt Gerrit's CSS. Details about themes
+are explained in the link:config-themes.html[Themes] section.
+
+Project-specific themes can only be installed by Gerrit administrators
+since the theme files must be copied into the Gerrit installation
+folder.
+
+[[tool-integration]]
+== Integration with other tools
+
+Gerrit provides many possibilities for the integration with other
+tools:
+
+- Stream Events:
++
+The link:cmd-stream-events.html[stream-events] SSH command allows to
+listen to Gerrit link:cmd-stream-events.html#events[events]. Other
+tools can use this to react on actions done in Gerrit.
++
+The link:access-control.html#capability_streamEvents[Stream Events]
+global capability is required for using the `stream-events` command.
+
+- REST API:
++
+Gerrit provides a rich link:rest-api.html[REST API] that other tools
+can use to query information from Gerrit and and to trigger actions in
+Gerrit.
+
+- Gerrit Plugins:
++
+The Gerrit functionality can be extended by plugins and there are many
+extension points, e.g. plugins can
++
+** link:dev-plugins.html#top-menu-extensions[add new menu entries]
+** link:dev-plugins.html#ui_extension[extend existing screens] and
+   link:dev-plugins.html#screen[add new screens]
+** link:config-validation.html[do validation], e.g. of new commits
+** add new REST endpoints and link:dev-plugins.html#ssh[SSH commands]
+
++
+How to develop a Gerrit plugin is described in the link:dev-plugins.html[
+Plugin Development] section.
+
+[[prject-lifecycle]]
+== Project Lifecycle
+
+[[project-creation]]
+=== Project Creation
+
+New projects can be created in the Gerrit WebUI under `Projects` >
+`Create Project`. The `Create Project` menu entry is only available if
+you have the link:access-control.html#capability_createProject[
+Create Project] global capability assigned.
+
+Projects can also be created via REST or SSH as described in the
+link:project-setup.html#project-creation[Project Setup] section.
+
+Creating the project with an initial empty commit is generally
+recommended because some tools have issues with cloning repositories
+that are completely empty. However, if you plan to link:#import-history[
+import an existing history] into the new project, it is better to
+create the project without an initial empty commit.
+
+[[import-history]]
+=== Import Existing History
+
+If you have an existing history you can import it into a Gerrit
+project. To do this you need to have a local Git repository that
+contains this history. If your existing codebase is in another VCS you
+must migrate it to Git first. For Subversion you can use the
+link:http://git-scm.com/book/en/Git-and-Other-Systems-Git-and-Subversion[
+git svn] command as described in the
+link:http://git-scm.com/book/en/Git-and-Other-Systems-Migrating-to-Git#Subversion[
+Subversion migration guide]. An importer for Perforce is available in
+the `contrib` section of the Git source code; how to use
+link:http://git-scm.com/docs/git-p4[git p4] to do the import from
+Perforce is described in the
+link:http://git-scm.com/book/en/Git-and-Other-Systems-Migrating-to-Git#Perforce[
+Perforce migration guide].
+
+To import an existing history into a Gerrit project you bypass code
+review and push it directly to `refs/heads/<branch>`. For this you must
+have the corresponding link:access-control.html#category_push_direct[
+Push] access right assigned. If the destination branch in the Gerrit
+repository already contains a history (e.g. an initial empty commit),
+you can overwrite it by doing a force push. In this case force push
+must be allowed in the access controls of the project.
+
+Some Gerrit servers may disallow forging committers by blocking the
+link:access-control.html#category_forge_committer[Forge Committer]
+access right globally. In this case you must use the
+link:https://www.kernel.org/pub/software/scm/git/docs/git-filter-branch.html[
+git filter-branch] command to rewrite the committer information for all
+commits (the author information that records who was writing the code
+stays intact; signed tags will lose their signature):
+
+====
+  $ git filter-branch --tag-name-filter cat --env-filter 'GIT_COMMITTER_NAME="John Doe"; GIT_COMMITTER_EMAIL="john.doe@example.com";' -- --all
+====
+
+If a link:config-gerrit.html#receive.maxObjectSizeLimit[max object size
+limit] is configured on the server you may need to remove large objects
+from the history before you are able to push. To find large objects in
+the history of your project you can use the
+link:https://gerrit.googlesource.com/gerrit/+/master/contrib/reposize.sh[
+reposize.sh] script from Gerrit's `contrib` folder. You can then use the
+link:https://www.kernel.org/pub/software/scm/git/docs/git-filter-branch.html[
+git filter-branch] command to remove the large objects from the history
+of all branches:
+
+====
+  $ git filter-branch -f --index-filter 'git rm --cached --ignore-unmatch path/to/large-file.jar' -- --all
+====
+
+Since this command rewrites all commits in the repository it's a good
+idea to create a fresh clone from this rewritten repository before
+pushing to Gerrit, this will ensure that the original objects which
+have been rewritten are removed.
+
+[[project-deletion]]
+=== Project Deletion
+
+Gerrit core does not support the deletion of projects.
+
+If the link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/delete-project[
+delete-project] plugin is installed, projects can be deleted from the
+Gerrit WebUI under `Projects` > `List` > <project> > `General` by
+clicking on the `Delete` command under `Project Commands`. The `Delete`
+command is only available if you have the `Delete Projects` global
+capability assigned, or if you own the project and you have the
+`Delete Own Projects` global capability assigned. If neither of these
+capabilities is granted, you need to contact a Gerrit administrator to
+request the deletion of your project.
+
+Instead of deleting a project you may set the
+link:project-setup.html#project-state[project state] to `ReadOnly` or
+`Hidden`.
+
+[[project-rename]]
+=== Project Rename
+
+Gerrit core does not support the renaming of projects.
+
+As workaround you may
+
+. 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]
+
+GERRIT
+------
+Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/js-api.txt b/Documentation/js-api.txt
index 957e14d..883198a 100644
--- a/Documentation/js-api.txt
+++ b/Documentation/js-api.txt
@@ -873,6 +873,10 @@
 === Gerrit.refresh()
 Redisplays the current web UI view, refreshing all information.
 
+[[Gerrit_refreshMenuBar]]
+=== Gerrit.refreshMenuBar()
+Refreshes Gerrit's menu bar.
+
 [[Gerrit_url]]
 === Gerrit.url()
 Returns the URL of the Gerrit Code Review server. If invoked with
diff --git a/Documentation/project-setup.txt b/Documentation/project-setup.txt
index 98ac504..25d455f 100644
--- a/Documentation/project-setup.txt
+++ b/Documentation/project-setup.txt
@@ -1,56 +1,61 @@
 = Gerrit Code Review - Project Configuration
 
-== Create Through SSH
+[[project-creation]]
+== Project Creation
 
-Creating a new repository over SSH is perhaps the easiest way to
-configure a new project:
+There are several ways to create a new project in Gerrit:
 
-====
-  ssh -p 29418 review.example.com gerrit create-project --name new/project
-====
+- in the Web UI under 'Projects' > 'Create Project'
+- via the link:rest-api-projects.html#create-project[Create Project]
+  REST endpoint
+- via the link:cmd-create-project.html[create-project] SSH command
 
-See link:cmd-create-project.html[gerrit create-project] for more
-details.
+To be able to create new projects the global capability
+link:access-control.html#capability_createProject[Create Project] must
+be granted.
 
+In addition, projects can be created link:#manual_project_creation[
+manually].
 
-== Manual Creation
+[[manual_project_creation]]
+=== Manual Project Creation
 
-Projects may also be manually created.
-
-=== Create Git Repository
-
-Create a Git repository under gerrit.basePath:
-
+. Create a Git repository under `gerrit.basePath`:
++
 ====
   git --git-dir=$base_path/new/project.git init
 ====
-
++
 [TIP]
 By tradition the repository directory name should have a `.git`
 suffix.
-
++
 To also make this repository available over the anonymous git://
 protocol, don't forget to create a `git-daemon-export-ok` file:
-
++
 ====
   touch $base_path/new/project.git/git-daemon-export-ok
 ====
 
-=== Register Project
-
+. Register Project
++
 Either restart the server, or flush the `project_list` cache:
-
++
 ====
   ssh -p 29418 localhost gerrit flush-caches --cache project_list
 ====
 
+[[project_options]]
+== Project Options
+
 [[submit_type]]
-== Change Submit Action
+=== Submit Type
 
 The method Gerrit uses to submit a change to a project can be
 modified by any project owner through the project console, `Projects` >
 `List` > my/project.  The following methods are supported:
 
+[[fast_forward_only]]
 * Fast Forward Only
 +
 This method produces a strictly linear history.  All merges must
@@ -60,6 +65,7 @@
 destination branch.  That is, the change must already contain the
 tip of the destination branch at submit time.
 
+[[merge_if_necessary]]
 * Merge If Necessary
 +
 This is the default for a new project.
@@ -69,6 +75,7 @@
 then a merge commit is automatically created.  This is identical
 to the classical `git merge` behavior, or `git merge --ff`.
 
+[[always_merge]]
 * Always Merge
 +
 Always produce a merge commit, even if the change is a strict
@@ -76,6 +83,7 @@
 behavior of `git merge --no-ff`, and may be useful if the
 project needs to follow submits with `git log --first-parent`.
 
+[[cherry_pick]]
 * Cherry Pick
 +
 Always cherry pick the patch set, ignoring the parent lineage
@@ -105,24 +113,153 @@
 succeed if there is no path conflict.  A path conflict occurs when
 the same file has also been changed on the other side of the merge.
 
+[[content_merge]]
 If `Automatically resolve conflicts` is enabled, Gerrit will try
 to do a content merge when a path conflict occurs.
 
+[[project-state]]
+=== State
 
-== Registering Additional Branches
+This setting defines the state of the project. A project can have the
+following states:
 
-Branches can be created over the SSH port by any `git push` client,
-if the user has been granted the `Create Reference` access right.
+- `Active`:
++
+The project is active and users can see and modify the project according
+to their access rights on the project.
 
-Additional branches can also be created through the web UI, assuming
-at least one commit already exists in the project repository.
-A project owner can create additional branches under `Projects` >
-`List` > my/project > `Branches`.  Enter the new branch name, and the
-starting Git revision.  Branch names that don't start with `refs/`
-will automatically have `refs/heads/` prefixed to ensure they are
-a standard Git branch name.  Almost any valid SHA-1 expression can
-be used to specify the starting revision, so long as it resolves
-to a commit object.  Abbreviated SHA-1s are not supported.
+- `Read Only`:
++
+The project is read only and all modifying operations on it are
+disabled. E.g. this means that pushing to this project fails for all
+users even if they have push permissions assigned on it.
++
+Setting a project to this state is an easy way to temporary close a
+project, as you can keep all write access rights in place and they will
+become active again as soon as the project state is set back to
+`Active`.
++
+This state also makes sense if a project was moved to another location.
+In this case all new development should happen in the new project and
+you want to prevent that somebody accidentally works on the old
+project, while keeping the old project around for old references.
+
+- `Hidden`:
++
+The project is hidden and only visible to project owners. Other users
+are not able to see the project even if they have read permissions
+granted on the project.
+
+=== Require Change-Id
+
+The `Require Change-Id in commit message` option defines whether a
+link:user-changeid.html[Change-Id] in the commit message is required
+for pushing a commit for review. If this option is set, trying to push
+a commit for review that doesn't contain a Change-Id in the commit
+message fails with link:error-missing-changeid.html[missing Change-Id
+in commit message footer].
+
+It is recommended to set this option and use a
+link:user-changeid.html#create[commit-msg hook] (or other client side
+tooling like EGit) to automatically generate Change-Id's for new
+commits. This way the Change-Id is automatically in place when changes
+are reworked or rebased and uploading new patch sets gets easy.
+
+If this option is not set, commits can be uploaded without a Change-Id,
+but then users have to remember to copy the assigned Change-Id from the
+change screen and insert it manually into the commit message when they
+want to upload a second patch set.
+
+=== Maximum Git Object Size Limit
+
+This option defines the maximum allowed Git object size that
+receive-pack will accept. If an object is larger than the given size
+the pack-parsing will abort and the push operation will fail.
+
+With this option users can be prevented from uploading commits that
+contain files which are too large.
+
+Normally the link:config-gerrit.html#receive.maxObjectSizeLimit[maximum
+Git object size limit] is configured globally for a Gerrit server. At
+the project level, the maximum Git object size limit can be further
+reduced, but not extended. The displayed effective limit shows the
+maximum Git object size limit that is actually used on the project.
+
+The defined maximum Git object size limit is inherited by any child
+project.
+
+=== Require Signed-off-by
+
+The `Require Signed-off-by in commit message` option defines whether a
+link:user-signedoffby.html[Signed-off-by] line in the commit message is
+required for pushing a commit. If this option is set, trying to push a
+commit that doesn't contain a Signed-off-by line in the commit message
+fails with link:error-not-signed-off-by.html[not Signed-off-by
+author/committer/uploader in commit message footer].
+
+[[branch-admin]]
+== Branch Administration
+
+[[branch-creation]]
+=== Branch Creation
+
+There are several ways to create a new branch in a project:
+
+- in the Web UI under 'Projects' > 'List' > <project> > 'Branches'
+- via the link:rest-api-projects.html#create-branch[Create Branch]
+  REST endpoint
+- via the link:cmd-create-branch.html[create-branch] SSH command
+- by using a git client to push a commit to a non-existing branch
+
+To be able to create new branches the user must have the
+link:access-control.html#category_create[Create Reference] access
+right. In addition, project owners and Gerrit administrators can create
+new branches from the Web UI or via REST even without having the
+`Create Reference` access right.
+
+When using the WebUI, the REST endpoint or the SSH command it is only
+possible to create branches on commits that already exist in the
+repository.
+
+If a branch name does not start with `refs/` it is automatically
+prefixed with `refs/heads/`.
+
+The starting revision for a new branch can be any valid SHA-1
+expression, as long as it resolves to a commit. Abbreviated SHA-1s
+are not supported.
+
+[[branch-deletion]]
+=== Branch Deletion
+
+There are several ways to delete a branch:
+
+- in the Web UI under 'Projects' > 'List' > <project> > 'Branches'
+- via the link:rest-api-projects.html#delete-branch[Delete Branch]
+  REST endpoint
+- by using a git client to force push nothing to an existing branch
++
+====
+  $ git push --force origin :refs/heads/<branch-to-delete>
+====
+
+To be able to delete branches, the user must have the
+link:access-control.html#category_push[Push] access right with the
+`force` option. In addition, project owners and Gerrit administrators
+can delete branches from the Web UI or via REST even without having the
+`Force Push` access right.
+
+[[default-branch]]
+=== Default Branch
+
+The default branch of a remote repository is defined by its `HEAD`.
+For convenience reasons, when the repository is cloned Git creates a
+local branch for this default branch and checks it out.
+
+Project owners can set `HEAD`
+
+- in the Web UI under 'Projects' > 'List' > <project> > 'Branches' or
+- via the link:rest-api-projects.html#set-head[Set HEAD] REST endpoint
+
 
 GERRIT
 ------
diff --git a/Documentation/prolog-cookbook.txt b/Documentation/prolog-cookbook.txt
index 91967b2..5bff6bf 100644
--- a/Documentation/prolog-cookbook.txt
+++ b/Documentation/prolog-cookbook.txt
@@ -1,5 +1,6 @@
 = Gerrit Code Review - Prolog Submit Rules Cookbook
 
+[[SubmitRule]]
 == Submit Rule
 A 'Submit Rule' in Gerrit is logic that defines when a change is submittable.
 By default, a change is submittable when it gets at least one
@@ -26,6 +27,7 @@
 link:http://gerrit-documentation.googlecode.com/svn/ReleaseNotes/ReleaseNotes-2.2.2.html[Gerrit
 2.2.2 ReleaseNotes] introduces Prolog support in Gerrit.
 
+[[SubmitType]]
 == Submit Type
 A 'Submit Type' is a strategy that is used on submit to integrate the
 change into the destination branch. Supported submit types are:
@@ -71,6 +73,7 @@
 also use the link:http://www.swi-prolog.org/[SWI-Prolog] environment. It
 provides a better shell interface and a graphical source-level debugger.
 
+[[RulesFile]]
 == The rules.pl file
 This section explains how to create and edit project specific submit rules. How
 to actually write the submit rules is explained in the next section.
@@ -644,6 +647,7 @@
 
 In the following examples both styles will be shown.
 
+[[NonAuthorCodeReview]]
 === Example 8: Make change submittable only if `Code-Review+2` is given by a non author
 In this example we introduce a new label `Non-Author-Code-Review` and make it
 satisfied if there is at least one `Code-Review+2` from a non author. All other
@@ -977,6 +981,7 @@
 ====
 
 
+[[SubmitTypePerBranch]]
 === Example 2: `Fast Forward Only` for all `refs/heads/stable*` branches
 For all `refs/heads/stable.*` branches we would like to enforce the `Fast
 Forward Only` submit type. A reason for this decision may be a need to never
diff --git a/Documentation/rest-api-access.txt b/Documentation/rest-api-access.txt
index 3ff3595..42214fe 100644
--- a/Documentation/rest-api-access.txt
+++ b/Documentation/rest-api-access.txt
@@ -268,7 +268,6 @@
     "MyProject": {
       "revision": "61157ed63e14d261b6dca40650472a9b0bd88474",
       "inherits_from": {
-        "kind": "gerritcodereview#project",
         "id": "All-Projects",
         "name": "All-Projects",
         "description": "Access inherited by all other projects."
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index 8f6b8a4..74a411f 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -2809,7 +2809,7 @@
 |===========================
 |Field Name    |Description
 |`message`     |Commit message for the cherry-picked change
-|`destination` |Destination Branch
+|`destination` |Destination branch
 |===========================
 
 [[comment-info]]
@@ -3093,6 +3093,8 @@
 |`value`       |optional|The voting value of the user who
 recommended/disliked this label on the change if it is not
 "`+1`"/"`-1`".
+|`default_value`|optional|The default voting value for the label.
+This value may be outside the range specified in permitted_labels.
 |===========================
 
 ==== Fields set by `DETAILED_LABELS`
diff --git a/Documentation/rest-api-groups.txt b/Documentation/rest-api-groups.txt
index d777db1..5ca3039 100644
--- a/Documentation/rest-api-groups.txt
+++ b/Documentation/rest-api-groups.txt
@@ -161,6 +161,24 @@
   }
 ----
 
+[[group-limit]]
+==== Group Limit
+The `/groups/` URL also accepts a limit integer in the `n` parameter.
+This limits the results to show `n` groups.
+
+Query the first 25 groups in group list.
+----
+  GET /groups/?n=25 HTTP/1.0
+----
+
+The `/groups/` URL also accepts a start integer in the `S` parameter.
+The results will skip `S` groups from group list.
+
+Query 25 groups starting from index 50.
+----
+  GET /groups/?n=25&S=50 HTTP/1.0
+----
+
 [[get-group]]
 === Get Group
 --
@@ -1068,7 +1086,7 @@
   Content-Type: application/json;charset=UTF-8
 
   {
-    "members": [
+    "groups": [
       "MyGroup",
       "MyOtherGroup"
     ]
diff --git a/Documentation/rest-api-projects.txt b/Documentation/rest-api-projects.txt
index 624cff9..a90dcab 100644
--- a/Documentation/rest-api-projects.txt
+++ b/Documentation/rest-api-projects.txt
@@ -35,21 +35,17 @@
   )]}'
   {
     "external/bison": {
-      "kind": "gerritcodereview#project",
       "id": "external%2Fbison",
       "description": "GNU parser generator"
     },
     "external/gcc": {
-      "kind": "gerritcodereview#project",
       "id": "external%2Fgcc",
     },
     "external/openssl": {
-      "kind": "gerritcodereview#project",
       "id": "external%2Fopenssl",
       "description": "encryption\ncrypto routines"
     },
     "test": {
-      "kind": "gerritcodereview#project",
       "id": "test",
       "description": "\u003chtml\u003e is escaped"
     }
@@ -81,11 +77,9 @@
   )]}'
   {
     "platform/drivers": {
-      "kind": "gerritcodereview#project",
       "id": "platform%2Fdrivers",
     },
     "platform/tools": {
-      "kind": "gerritcodereview#project",
       "id": "platform%2Ftools",
     }
   }
@@ -132,11 +126,11 @@
 
   )]}'
   {
-    "kind": "gerritcodereview#project",
     "id": "plugins%2Freplication",
     "name": "plugins/replication",
     "parent": "Public-Plugins",
-    "description": "Copies to other servers using the Git protocol"
+    "description": "Copies to other servers using the Git protocol",
+    "state": "ACTIVE"
   }
 ----
 
@@ -176,7 +170,6 @@
 
   )]}'
   {
-    "kind": "gerritcodereview#project",
     "id": "MyProject",
     "name": "MyProject",
     "parent": "All-Projects",
@@ -798,21 +791,18 @@
   )]}'
   [
     {
-      "kind": "gerritcodereview#project",
       "id": "plugins%2Freplication",
       "name": "plugins/replication",
       "parent": "Public-Plugins",
       "description": "Copies to other servers using the Git protocol"
     },
     {
-      "kind": "gerritcodereview#project",
       "id": "plugins%2Freviewnotes",
       "name": "plugins/reviewnotes",
       "parent": "Public-Plugins",
       "description": "Annotates merged commits using notes on refs/notes/review."
     },
     {
-      "kind": "gerritcodereview#project",
       "id": "plugins%2Fsingleusergroup",
       "name": "plugins/singleusergroup",
       "parent": "Public-Plugins",
@@ -841,35 +831,30 @@
   )]}'
   [
     {
-      "kind": "gerritcodereview#project",
       "id": "gerrit",
       "name": "gerrit",
       "parent": "Public-Projects",
       "description": "Gerrit Code Review"
     },
     {
-      "kind": "gerritcodereview#project",
       "id": "plugins%2Freplication",
       "name": "plugins/replication",
       "parent": "Public-Plugins",
       "description": "Copies to other servers using the Git protocol"
     },
     {
-      "kind": "gerritcodereview#project",
       "id": "plugins%2Freviewnotes",
       "name": "plugins/reviewnotes",
       "parent": "Public-Plugins",
       "description": "Annotates merged commits using notes on refs/notes/review."
     },
     {
-      "kind": "gerritcodereview#project",
       "id": "plugins%2Fsingleusergroup",
       "name": "plugins/singleusergroup",
       "parent": "Public-Plugins",
       "description": "GroupBackend enabling users to be directly added to access rules"
     },
     {
-      "kind": "gerritcodereview#project",
       "id": "Public-Plugins",
       "name": "Public-Plugins",
       "parent": "Public-Projects",
@@ -903,7 +888,6 @@
 
   )]}'
   {
-    "kind": "gerritcodereview#project",
     "id": "plugins%2Freplication",
     "name": "plugins/replication",
     "parent": "Public-Plugins",
@@ -1490,7 +1474,6 @@
 [options="header",width="50%",cols="1,^2,4"]
 |===========================
 |Field Name    ||Description
-|`kind`        ||`gerritcodereview#project`
 |`id`          ||The URL encoded project name.
 |`name`        |
 not set if returned in a map where the project name is used as map key|
@@ -1500,6 +1483,7 @@
 `?-<n>` if the parent project is not visible (`<n>` is a number which
 is increased for each non-visible project).
 |`description` |optional|The description of the project.
+|`state`       |optional|`ACTIVE`, `READ_ONLY` or `HIDDEN`.
 |`branches`    |optional|Map of branch names to HEAD revisions.
 |'web_links'   |optional|
 Links to the project in external sites as a list of
diff --git a/Documentation/user-notify.txt b/Documentation/user-notify.txt
index 2f8c162..dd7c4c6 100644
--- a/Documentation/user-notify.txt
+++ b/Documentation/user-notify.txt
@@ -6,6 +6,7 @@
 uploaded for review, after comments have been posted on a change,
 or after the change has been submitted to a branch.
 
+[[user]]
 == User Level Settings
 
 Individual users can configure email subscriptions by editing
@@ -27,6 +28,7 @@
 Write' option in the user preferences.
 
 
+[[project]]
 == Project Level Settings
 
 Project owners and site administrators can configure project level
diff --git a/Documentation/user-search.txt b/Documentation/user-search.txt
index 2c3d25c..9831d81 100644
--- a/Documentation/user-search.txt
+++ b/Documentation/user-search.txt
@@ -265,7 +265,7 @@
 True on any change where the current user is a reviewer.
 Same as `reviewer:self`.
 
-is:open::
+is:open, is:pending::
 +
 True if the change is either open or submitted, merge pending.
 
@@ -287,7 +287,7 @@
 destination branch.
 
 [[status]]
-status:open::
+status:open, status:pending::
 +
 True if the change state is either 'review in progress' or 'submitted,
 merge pending'.
diff --git a/contrib/reposize.sh b/contrib/reposize.sh
new file mode 100755
index 0000000..3699edc
--- /dev/null
+++ b/contrib/reposize.sh
@@ -0,0 +1,57 @@
+#!/bin/bash
+# Shows you the largest objects in your repo's pack files.
+#
+# usage:
+#      $ git-find-big-blobs 100		# find and list biggest 100 objects
+# derived from
+# http://stubbisms.wordpress.com/2009/07/10/git-script-to-show-largest-pack-objects-and-trim-your-waist-line/
+
+if [ ! $# == 1 ]; then
+    echo "
+    Usage: $0 <number of biggest objects to show>
+        if there are loose objects the script will run 'git gc' to move all data to packs
+"
+    exit
+fi
+
+# find git repository directory
+gitdir=$(git rev-parse --git-dir 2>.error.log)
+if [ $? -ne 0 ]; then
+    echo $(cat .error.log)
+    rm .error.log
+    exit
+fi
+rm .error.log
+
+object_count=$(git count-objects -v | grep count: | cut -f 2 -d ' ')
+if [ $object_count -gt 1 ]; then
+    echo "-------------------------------------------------------"
+    echo "$object_count loose objects found in repository $gitdir"
+    echo "-> running git gc to move all data to packs"
+    git gc
+    echo "-------------------------------------------------------"
+fi
+
+# set the internal field separator to line break, so that we can iterate easily over the verify-pack output
+IFS=$'\n';
+
+# list all objects including their size, sort by size, take top $1 biggest blobs
+objects=$(git verify-pack -v $gitdir/objects/pack/pack-*.idx | grep -v chain | sort -k3nr | head -n $1)
+
+echo "All sizes are in kB's. The pack column is the size of the object, compressed, inside the pack file."
+
+output="size,pack,SHA,location"
+for y in $objects
+do
+    # extract the size in bytes
+    size=$(($(echo $y | cut -f 5 -d ' ') / 1024))
+    # extract the compressed size in bytes
+    compressedSize=$(($(echo $y | cut -f 6 -d ' ') / 1024))
+    # extract the SHA
+    sha=$(echo $y | cut -f 1 -d ' ')
+    # find the objects location in the repository tree
+    other=$(git rev-list --all --objects | grep $sha)
+    output="${output}\n${size},${compressedSize},${other}"
+done
+
+echo -e $output | column -t -s ', '
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AcceptanceTestRequestScope.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AcceptanceTestRequestScope.java
index 63bdfd2..6ee7efa 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AcceptanceTestRequestScope.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AcceptanceTestRequestScope.java
@@ -130,8 +130,7 @@
     }
   }
 
-  private static final ThreadLocal<Context> current =
-      new ThreadLocal<Context>();
+  private static final ThreadLocal<Context> current = new ThreadLocal<>();
 
   private static Context requireContext() {
     final Context ctx = current.get();
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java
index a8ce229..cbf2685 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java
@@ -36,7 +36,6 @@
 import java.lang.reflect.Field;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
-import java.net.ServerSocket;
 import java.net.URI;
 import java.net.UnknownHostException;
 import java.util.concurrent.BrokenBarrierException;
@@ -123,23 +122,18 @@
 
   private static void mergeTestConfig(Config cfg)
       throws IOException {
-    InetSocketAddress http = newPort();
-    InetSocketAddress sshd = newPort();
-    String url = "http://" + format(http) + "/";
-
+    String forceEphemeralPort = String.format("%s:0",
+        getLocalHost().getHostName());
+    String url = "http://" + forceEphemeralPort + "/";
     cfg.setString("gerrit", null, "canonicalWebUrl", url);
     cfg.setString("httpd", null, "listenUrl", url);
-    cfg.setString("sshd", null, "listenAddress", format(sshd));
+    cfg.setString("sshd", null, "listenAddress", forceEphemeralPort);
     cfg.setString("cache", null, "directory", null);
     cfg.setBoolean("sendemail", null, "enable", false);
     cfg.setInt("cache", "projects", "checkFrequency", 0);
     cfg.setInt("plugins", null, "checkFrequency", 0);
   }
 
-  private static String format(InetSocketAddress s) {
-    return String.format("%s:%d", s.getAddress().getHostAddress(), s.getPort());
-  }
-
   private static Injector createTestInjector(Daemon daemon) throws Exception {
     Injector sysInjector = get(daemon, "sysInjector");
     Module module = new FactoryModule() {
@@ -160,15 +154,6 @@
     return (T) f.get(obj);
   }
 
-  private static final InetSocketAddress newPort() throws IOException {
-    ServerSocket s = new ServerSocket(0, 0, getLocalHost());
-    try {
-      return (InetSocketAddress) s.getLocalSocketAddress();
-    } finally {
-      s.close();
-    }
-  }
-
   private static InetAddress getLocalHost() throws UnknownHostException {
     return InetAddress.getLoopbackAddress();
   }
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/BUCK
index aa9703c..1152d88 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/BUCK
@@ -2,5 +2,5 @@
 
 acceptance_tests(
   srcs = glob(['*IT.java']),
-  deps = ['//gerrit-acceptance-tests:lib'],
+  labels = ['api'],
 )
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
index 6dff20a..2f66b7d 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -48,6 +48,7 @@
     assertEquals(true, c.mergeable);
     assertEquals(r.getChangeId(), c.changeId);
     assertEquals(c.created, c.updated);
+    assertEquals(1, c._number);
   }
 
   @Test
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/project/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/project/BUCK
index 8da456d..1152d88 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/project/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/project/BUCK
@@ -2,6 +2,5 @@
 
 acceptance_tests(
   srcs = glob(['*IT.java']),
-  deps = ['//gerrit-acceptance-tests:lib'],
+  labels = ['api'],
 )
-
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/BUCK
index aa9703c..1152d88 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/BUCK
@@ -2,5 +2,5 @@
 
 acceptance_tests(
   srcs = glob(['*IT.java']),
-  deps = ['//gerrit-acceptance-tests:lib'],
+  labels = ['api'],
 )
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/BUCK
index 5976f54..3ead2a1 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/BUCK
@@ -2,12 +2,13 @@
 
 acceptance_tests(
   srcs = ['DraftChangeBlockedIT.java', 'SubmitOnPushIT.java'],
-  deps = ['//gerrit-acceptance-tests:lib'],
+  labels = ['git'],
 )
 
 acceptance_tests(
   srcs = ['HttpPushForReviewIT.java', 'SshPushForReviewIT.java'],
   deps = [':push_for_review'],
+  labels = ['git'],
 )
 
 java_library(
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/pgm/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/pgm/BUCK
new file mode 100644
index 0000000..00b53f9
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/pgm/BUCK
@@ -0,0 +1,7 @@
+include_defs('//gerrit-acceptance-tests/tests.defs')
+
+acceptance_tests(
+  srcs = glob(['*IT.java']),
+  labels = ['pgm'],
+  source_under_test = ['//gerrit-pgm:pgm'],
+)
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/pgm/ReindexIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/pgm/ReindexIT.java
new file mode 100644
index 0000000..5778b19
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/pgm/ReindexIT.java
@@ -0,0 +1,66 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.acceptance.pgm;
+
+import static org.junit.Assert.assertEquals;
+
+import com.google.gerrit.acceptance.TempFileUtil;
+import com.google.gerrit.launcher.GerritLauncher;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+
+public class ReindexIT {
+  private File sitePath;
+
+  @Before
+  public void createTempDirectory() throws Exception {
+    sitePath = TempFileUtil.createTempDirectory();
+  }
+
+  @After
+  public void destroySite() throws Exception {
+    if (sitePath != null) {
+      TempFileUtil.recursivelyDelete(sitePath);
+    }
+  }
+
+  @Test
+  public void reindexEmptySite() throws Exception {
+    initSite();
+    runGerrit("reindex", "-d", sitePath.getPath(),
+        "--show-stack-trace");
+  }
+
+  @Test
+  public void reindexEmptySiteWithRecheckMergeable() throws Exception {
+    initSite();
+    runGerrit("reindex", "-d", sitePath.getPath(),
+        "--show-stack-trace",
+        "--recheck-mergeable");
+  }
+
+  private void initSite() throws Exception {
+    runGerrit("init", "-d", sitePath.getPath(),
+        "--batch", "--no-auto-start", "--skip-plugins", "--show-stack-trace");
+  }
+
+  private static void runGerrit(String... args) throws Exception {
+    assertEquals(0, GerritLauncher.mainImpl(args));
+  }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/BUCK
index 77e0419..f081ada 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/BUCK
@@ -2,10 +2,8 @@
 
 acceptance_tests(
   srcs = glob(['*IT.java']),
-  deps = [
-    ':util',
-    '//gerrit-acceptance-tests:lib',
-  ],
+  deps = [':util'],
+  labels = ['rest']
 )
 
 java_library(
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/BUCK
index c76c9a6..d63d195 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/BUCK
@@ -10,17 +10,15 @@
 
 acceptance_tests(
   srcs = OTHER_TESTS,
-  deps = [
-    '//gerrit-acceptance-tests:lib',
-  ],
+  labels = ['rest'],
 )
 
 acceptance_tests(
   srcs = SUBMIT_TESTS,
   deps = [
     ':submit_util',
-    '//gerrit-acceptance-tests:lib',
   ],
+  labels = ['rest'],
 )
 
 java_library(
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/BUCK
index 108cc8d..da34c1d 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/BUCK
@@ -6,6 +6,7 @@
     ':util',
     '//gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account:util',
   ],
+  labels = ['rest']
 )
 
 java_library(
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/BUCK
index 91511be..fa8b10e 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/BUCK
@@ -5,8 +5,8 @@
   deps = [
     ':branch',
     ':project',
-    '//gerrit-acceptance-tests:lib',
   ],
+  labels = ['rest']
 )
 
 java_library(
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/BUCK
index 688e649..fce853b 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/change/BUCK
@@ -2,7 +2,5 @@
 
 acceptance_tests(
   srcs = glob(['*IT.java']),
-  deps = [
-    '//gerrit-acceptance-tests:lib',
-  ],
+  labels = ['server'],
 )
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/BUCK
index 688e649..fce853b 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/BUCK
@@ -2,7 +2,5 @@
 
 acceptance_tests(
   srcs = glob(['*IT.java']),
-  deps = [
-    '//gerrit-acceptance-tests:lib',
-  ],
+  labels = ['server'],
 )
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/LabelTypeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/LabelTypeIT.java
index a2dd8ec..7240036 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/LabelTypeIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/LabelTypeIT.java
@@ -29,14 +29,23 @@
 import com.google.gerrit.server.git.MetaDataUpdate;
 import com.google.gerrit.server.git.ProjectConfig;
 import com.google.gerrit.server.project.ProjectCache;
+import com.google.gerrit.testutil.ConfigSuite;
 import com.google.inject.Inject;
 
+import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.Repository;
 import org.junit.Before;
 import org.junit.Test;
 
 @NoHttpd
 public class LabelTypeIT extends AbstractDaemonTest {
+  @ConfigSuite.Config
+  public static Config noteDbEnabled() {
+    Config cfg = new Config();
+    cfg.setBoolean("notedb", null, "write", true);
+    cfg.setBoolean("notedb", "patchSetApprovals", "read", true);
+    return cfg;
+  }
 
   @Inject
   private GitRepositoryManager repoManager;
@@ -60,6 +69,7 @@
     codeReview.setCopyMaxScore(false);
     codeReview.setCopyAllScoresOnTrivialRebase(false);
     codeReview.setCopyAllScoresIfNoCodeChange(false);
+    codeReview.setDefaultValue((short)-1);
     saveProjectConfig(cfg);
   }
 
@@ -78,7 +88,7 @@
     saveLabelConfig();
     PushOneCommit.Result r = createChange();
     revision(r).review(ReviewInput.reject());
-    assertApproval(r, -2);
+    //assertApproval(r, -2);
     r = amendChange(r.getChangeId());
     assertApproval(r, -2);
   }
@@ -255,6 +265,7 @@
     // through JSON instead of querying the DB directly.
     ChangeInfo c = get(r.getChangeId());
     LabelInfo cr = c.labels.get("Code-Review");
+    assertEquals(-1, (int) cr.defaultValue);
     assertEquals(1, cr.all.size());
     assertEquals("Administrator", cr.all.get(0).name);
     assertEquals(expected, cr.all.get(0).value.intValue());
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/BUCK
index aa9703c..74b26ba6 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/BUCK
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/BUCK
@@ -3,4 +3,5 @@
 acceptance_tests(
   srcs = glob(['*IT.java']),
   deps = ['//gerrit-acceptance-tests:lib'],
+  labels = ['ssh'],
 )
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/JschVerifyFalseBugIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/JschVerifyFalseBugIT.java
new file mode 100644
index 0000000..9bbc125
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/JschVerifyFalseBugIT.java
@@ -0,0 +1,67 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.acceptance.ssh;
+
+import static com.google.gerrit.acceptance.GitUtil.cloneProject;
+import static com.google.gerrit.acceptance.GitUtil.createProject;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.NoHttpd;
+
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+@NoHttpd
+// To see this test failing with 'verify: false', at least in the Jcsh 0.1.51
+// remove bouncycastle libs from the classpath, and run:
+// buck test //gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh:JschVerifyFalseBugIT
+public class JschVerifyFalseBugIT extends AbstractDaemonTest {
+
+  @Test
+  @Ignore// we know it works now, so let's not clone a project 500 times ;-)
+  public void test() throws Exception {
+    test(5);
+  }
+
+  private void test(int threads) throws InterruptedException,
+      ExecutionException {
+    Callable<Void> task = new Callable<Void>() {
+      @Override
+      public Void call() throws Exception {
+        for (int i = 1; i < 100; i++) {
+          String p = "p" + i;
+          createProject(sshSession, p);
+          cloneProject(sshSession.getUrl() + "/" + p);
+        }
+        return null;
+      }
+    };
+    List<Callable<Void>> nCopies = Collections.nCopies(threads, task);
+    List<Future<Void>> futures = Executors.newFixedThreadPool(threads)
+        .invokeAll(nCopies);
+    for (Future<Void> future : futures) {
+      future.get();
+    }
+    Assert.assertEquals(threads, futures.size());
+  }
+}
diff --git a/gerrit-acceptance-tests/tests.defs b/gerrit-acceptance-tests/tests.defs
index 3c8b4d5..7bd2430 100644
--- a/gerrit-acceptance-tests/tests.defs
+++ b/gerrit-acceptance-tests/tests.defs
@@ -1,7 +1,21 @@
+# These are needed as workaround for the 'verify: false' bug in Jcraft SSH library
+BOUNCYCASTLE = [
+  '//lib/bouncycastle:bcpkix',
+  '//lib/bouncycastle:bcpg',
+]
+
 def acceptance_tests(
     srcs,
     deps = [],
+    labels = [],
+    source_under_test = [],
     vm_args = ['-Xmx256m']):
+  from os import environ, path
+  if not environ.get('NO_BOUNCYCASTLE'):
+    deps = BOUNCYCASTLE + deps
+  if path.exists('/dev/urandom'):
+    vm_args = vm_args + ['-Djava.security.egd=file:/dev/./urandom']
+
   for j in srcs:
     java_test(
       name = j[:-len('.java')],
@@ -11,8 +25,8 @@
         '//gerrit-httpd:httpd',
         '//gerrit-sshd:sshd',
         '//gerrit-server:server',
-      ],
-      labels = [
+      ] + source_under_test,
+      labels = labels + [
         'acceptance',
         'slow',
       ],
diff --git a/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java b/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java
index cb209e2..85e4599 100644
--- a/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java
+++ b/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java
@@ -212,6 +212,6 @@
       long maxSize) {
     File db = new File(cacheDir, name).getAbsoluteFile();
     String url = "jdbc:h2:" + db.toURI().toString();
-    return new SqlStore<K, V>(url, keyType, maxSize);
+    return new SqlStore<>(url, keyType, maxSize);
   }
 }
diff --git a/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java b/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java
index 4aca42b..de7613d 100644
--- a/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java
+++ b/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java
@@ -115,7 +115,7 @@
 
   @Override
   public void put(final K key, V val) {
-    final ValueHolder<V> h = new ValueHolder<V>(val);
+    final ValueHolder<V> h = new ValueHolder<>(val);
     h.created = TimeUtil.nowMs();
     mem.put(key, h);
     executor.execute(new Runnable() {
@@ -246,7 +246,7 @@
         }
       }
 
-      final ValueHolder<V> h = new ValueHolder<V>(loader.load(key));
+      final ValueHolder<V> h = new ValueHolder<>(loader.load(key));
       h.created = TimeUtil.nowMs();
       executor.execute(new Runnable() {
         @Override
@@ -302,7 +302,7 @@
       return (KeyType<K>) OTHER;
     }
 
-    static final KeyType<?> OTHER = new KeyType<Object>();
+    static final KeyType<?> OTHER = new KeyType<>();
     static final KeyType<String> STRING = new KeyType<String>() {
       @Override
       String columnType() {
@@ -346,7 +346,7 @@
 
       int cores = Runtime.getRuntime().availableProcessors();
       int keep = Math.min(cores, 16);
-      this.handles = new ArrayBlockingQueue<SqlHandle>(keep);
+      this.handles = new ArrayBlockingQueue<>(keep);
     }
 
     synchronized void open() {
@@ -440,7 +440,7 @@
 
           @SuppressWarnings("unchecked")
           V val = (V) r.getObject(1);
-          ValueHolder<V> h = new ValueHolder<V>(val);
+          ValueHolder<V> h = new ValueHolder<>(val);
           h.clean = true;
           hitCount.incrementAndGet();
           touch(c, key);
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/LabelType.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/LabelType.java
index c596c1e..28629b9 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/LabelType.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/LabelType.java
@@ -108,6 +108,7 @@
   protected boolean copyMaxScore;
   protected boolean copyAllScoresOnTrivialRebase;
   protected boolean copyAllScoresIfNoCodeChange;
+  protected short defaultValue;
 
   protected List<LabelValue> values;
   protected short maxNegative;
@@ -125,6 +126,7 @@
     this.name = checkName(name);
     canOverride = true;
     values = sortValues(valueList);
+    defaultValue = 0;
 
     abbreviation = defaultAbbreviation(name);
     functionName = "MaxWithBlock";
@@ -200,6 +202,14 @@
     return v.getValue() > 0 ? v : null;
   }
 
+  public short getDefaultValue() {
+    return defaultValue;
+  }
+
+  public void setDefaultValue(short defaultValue) {
+    this.defaultValue = defaultValue;
+  }
+
   public boolean isCopyMinScore() {
     return copyMinScore;
   }
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/LabelTypes.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/LabelTypes.java
index b47445e..18928f2 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/LabelTypes.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/LabelTypes.java
@@ -33,7 +33,7 @@
 
   public LabelTypes(final List<? extends LabelType> approvals) {
     labelTypes =
-        Collections.unmodifiableList(new ArrayList<LabelType>(approvals));
+        Collections.unmodifiableList(new ArrayList<>(approvals));
   }
 
   public List<LabelType> getLabelTypes() {
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/Permission.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/Permission.java
index 0326e02..2379b4a 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/Permission.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/Permission.java
@@ -48,7 +48,7 @@
   private static final int labelAsIndex;
 
   static {
-    NAMES_LC = new ArrayList<String>();
+    NAMES_LC = new ArrayList<>();
     NAMES_LC.add(OWNER.toLowerCase());
     NAMES_LC.add(READ.toLowerCase());
     NAMES_LC.add(ABANDON.toLowerCase());
@@ -229,7 +229,7 @@
 
   private void initRules() {
     if (rules == null) {
-      rules = new ArrayList<PermissionRule>(4);
+      rules = new ArrayList<>(4);
     }
   }
 
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/GerritApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/GerritApi.java
index 844807b..cc5807b 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/GerritApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/GerritApi.java
@@ -14,10 +14,34 @@
 
 package com.google.gerrit.extensions.api;
 
+import com.google.gerrit.extensions.api.accounts.Accounts;
 import com.google.gerrit.extensions.api.changes.Changes;
 import com.google.gerrit.extensions.api.projects.Projects;
+import com.google.gerrit.extensions.restapi.NotImplementedException;
 
 public interface GerritApi {
+  public Accounts accounts();
   public Changes changes();
   public Projects projects();
+
+  /**
+   * A default implementation which allows source compatibility
+   * when adding new methods to the interface.
+   **/
+  public class NotImplemented implements GerritApi {
+    @Override
+    public Accounts accounts() {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public Changes changes() {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public Projects projects() {
+      throw new NotImplementedException();
+    }
+  }
 }
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/AccountApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/AccountApi.java
new file mode 100644
index 0000000..d571cfd
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/AccountApi.java
@@ -0,0 +1,47 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.extensions.api.accounts;
+
+import com.google.gerrit.extensions.common.AccountInfo;
+import com.google.gerrit.extensions.restapi.NotImplementedException;
+import com.google.gerrit.extensions.restapi.RestApiException;
+
+public interface AccountApi {
+  AccountInfo get() throws RestApiException;
+
+  void starChange(String id) throws RestApiException;
+  void unstarChange(String id) throws RestApiException;
+
+  /**
+   * A default implementation which allows source compatibility
+   * when adding new methods to the interface.
+   **/
+  public class NotImplemented implements AccountApi {
+    @Override
+    public AccountInfo get() throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public void starChange(String id) throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public void unstarChange(String id) throws RestApiException {
+      throw new NotImplementedException();
+    }
+  }
+}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/Accounts.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/Accounts.java
new file mode 100644
index 0000000..749b12a
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/Accounts.java
@@ -0,0 +1,39 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.extensions.api.accounts;
+
+import com.google.gerrit.extensions.restapi.NotImplementedException;
+import com.google.gerrit.extensions.restapi.RestApiException;
+
+public interface Accounts {
+  AccountApi id(String id) throws RestApiException;
+  AccountApi self() throws RestApiException;
+
+  /**
+   * A default implementation which allows source compatibility
+   * when adding new methods to the interface.
+   **/
+  public class NotImplemented implements Accounts {
+    @Override
+    public AccountApi id(String id) throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public AccountApi self() throws RestApiException {
+      throw new NotImplementedException();
+    }
+  }
+}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
index f0a9e4d..3382b76 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
@@ -16,6 +16,7 @@
 
 import com.google.gerrit.extensions.common.ChangeInfo;
 import com.google.gerrit.extensions.common.ListChangesOption;
+import com.google.gerrit.extensions.restapi.NotImplementedException;
 import com.google.gerrit.extensions.restapi.RestApiException;
 
 import java.util.EnumSet;
@@ -45,4 +46,85 @@
   ChangeInfo get() throws RestApiException;
   /** {@code get} with {@link ListChangesOption} set to NONE. */
   ChangeInfo info() throws RestApiException;
+
+  /**
+   * A default implementation which allows source compatibility
+   * when adding new methods to the interface.
+   **/
+  public class NotImplemented implements ChangeApi {
+    @Override
+    public String id() {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public RevisionApi current() throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public RevisionApi revision(int id) throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public RevisionApi revision(String id) throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public void abandon() throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public void abandon(AbandonInput in) throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public void restore() throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public void restore(RestoreInput in) throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public ChangeApi revert() throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public ChangeApi revert(RevertInput in) throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public void addReviewer(AddReviewerInput in) throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public void addReviewer(String in) throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public ChangeInfo get(EnumSet<ListChangesOption> options) throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public ChangeInfo get() throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public ChangeInfo info() throws RestApiException {
+      throw new NotImplementedException();
+    }
+  }
 }
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/Changes.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/Changes.java
index 48e9fd3..9debb6b 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/Changes.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/Changes.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.extensions.api.changes;
 
+import com.google.gerrit.extensions.restapi.NotImplementedException;
 import com.google.gerrit.extensions.restapi.RestApiException;
 
 public interface Changes {
@@ -21,4 +22,25 @@
   ChangeApi id(String triplet) throws RestApiException;
   ChangeApi id(String project, String branch, String id)
       throws RestApiException;
+
+  /**
+   * A default implementation which allows source compatibility
+   * when adding new methods to the interface.
+   **/
+  public class NotImplemented implements Changes {
+    @Override
+    public ChangeApi id(int id) throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public ChangeApi id(String triplet) throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public ChangeApi id(String project, String branch, String id) throws RestApiException {
+      throw new NotImplementedException();
+    }
+  }
 }
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ReviewInput.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ReviewInput.java
index 993fa14..9a88b0c 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ReviewInput.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ReviewInput.java
@@ -97,7 +97,7 @@
       throw new IllegalArgumentException();
     }
     if (labels == null) {
-      labels = new LinkedHashMap<String, Short>(4);
+      labels = new LinkedHashMap<>(4);
     }
     labels.put(name, value);
     return this;
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
index dc2a9a7..a2a96f9 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.extensions.api.changes;
 
+import com.google.gerrit.extensions.restapi.NotImplementedException;
 import com.google.gerrit.extensions.restapi.RestApiException;
 
 public interface RevisionApi {
@@ -27,4 +28,50 @@
   ChangeApi cherryPick(CherryPickInput in) throws RestApiException;
   ChangeApi rebase() throws RestApiException;
   boolean canRebase();
+
+  /**
+   * A default implementation which allows source compatibility
+   * when adding new methods to the interface.
+   **/
+  public class NotImplemented implements RevisionApi {
+    @Override
+    public void delete() throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public void review(ReviewInput in) throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public void submit() throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public void submit(SubmitInput in) throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public void publish() throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public ChangeApi cherryPick(CherryPickInput in) throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public ChangeApi rebase() throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public boolean canRebase() {
+      throw new NotImplementedException();
+    }
+  }
 }
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/BranchApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/BranchApi.java
index 2f1533f..f88a2cb 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/BranchApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/BranchApi.java
@@ -14,8 +14,20 @@
 
 package com.google.gerrit.extensions.api.projects;
 
+import com.google.gerrit.extensions.restapi.NotImplementedException;
 import com.google.gerrit.extensions.restapi.RestApiException;
 
 public interface BranchApi {
   BranchApi create(BranchInput in) throws RestApiException;
+
+  /**
+   * A default implementation which allows source compatibility
+   * when adding new methods to the interface.
+   **/
+  public class NotImplemented implements BranchApi {
+    @Override
+    public BranchApi create(BranchInput in) throws RestApiException {
+      throw new NotImplementedException();
+    }
+  }
 }
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectApi.java
index aee5405..d013c5d 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ProjectApi.java
@@ -15,6 +15,7 @@
 package com.google.gerrit.extensions.api.projects;
 
 import com.google.gerrit.extensions.common.ProjectInfo;
+import com.google.gerrit.extensions.restapi.NotImplementedException;
 import com.google.gerrit.extensions.restapi.RestApiException;
 
 public interface ProjectApi {
@@ -22,4 +23,30 @@
   ProjectApi create(ProjectInput in) throws RestApiException;
   ProjectInfo get();
   BranchApi branch(String ref);
+
+  /**
+   * A default implementation which allows source compatibility
+   * when adding new methods to the interface.
+   **/
+  public class NotImplemented implements ProjectApi {
+    @Override
+    public ProjectApi create() throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public ProjectApi create(ProjectInput in) throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public ProjectInfo get() {
+      throw new NotImplementedException();
+    }
+
+    @Override
+    public BranchApi branch(String ref) {
+      throw new NotImplementedException();
+    }
+  }
 }
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/Projects.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/Projects.java
index a3a4137..a0f22b9 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/Projects.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/Projects.java
@@ -14,8 +14,20 @@
 
 package com.google.gerrit.extensions.api.projects;
 
+import com.google.gerrit.extensions.restapi.NotImplementedException;
 import com.google.gerrit.extensions.restapi.RestApiException;
 
 public interface Projects {
   ProjectApi name(String name) throws RestApiException;
+
+  /**
+   * A default implementation which allows source compatibility
+   * when adding new methods to the interface.
+   **/
+  public class NotImplemented implements Projects {
+    @Override
+    public ProjectApi name(String name) throws RestApiException {
+      throw new NotImplementedException();
+    }
+  }
 }
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ChangeInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ChangeInfo.java
index f85684e..653ec37 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ChangeInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ChangeInfo.java
@@ -39,4 +39,5 @@
   public Map<String, LabelInfo> labels;
   public Collection<ChangeMessageInfo> messages;
   public Map<String, RevisionInfo> revisions;
+  public int _number;
 }
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/LabelInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/LabelInfo.java
index fd6008f..1e4edcd 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/LabelInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/LabelInfo.java
@@ -25,6 +25,7 @@
   public List<ApprovalInfo> all;
   public Map<String, String> values;
   public Short value;
+  public Short defaultValue;
   public Boolean optional;
   public Boolean blocking;
 }
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicItem.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicItem.java
index 91bf7a6..9ef7d1b 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicItem.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicItem.java
@@ -78,7 +78,7 @@
     Key<DynamicItem<T>> key = (Key<DynamicItem<T>>) Key.get(
         Types.newParameterizedType(DynamicItem.class, member.getType()));
     binder.bind(key)
-      .toProvider(new DynamicItemProvider<T>(member, key))
+      .toProvider(new DynamicItemProvider<>(member, key))
       .in(Scopes.SINGLETON);
   }
 
@@ -111,10 +111,10 @@
   DynamicItem(Key<DynamicItem<T>> key, Provider<T> provider, String pluginName) {
     NamedProvider<T> in = null;
     if (provider != null) {
-      in = new NamedProvider<T>(provider, pluginName);
+      in = new NamedProvider<>(provider, pluginName);
     }
     this.key = key;
-    this.ref = new AtomicReference<NamedProvider<T>>(in);
+    this.ref = new AtomicReference<>(in);
   }
 
   /**
@@ -148,7 +148,7 @@
    * @return handle to remove the item at a later point in time.
    */
   public RegistrationHandle set(Provider<T> impl, String pluginName) {
-    final NamedProvider<T> item = new NamedProvider<T>(impl, pluginName);
+    final NamedProvider<T> item = new NamedProvider<>(impl, pluginName);
     NamedProvider<T> old = null;
     while (!ref.compareAndSet(old, item)) {
       old = ref.get();
@@ -180,7 +180,7 @@
    */
   public ReloadableRegistrationHandle<T> set(Key<T> key, Provider<T> impl,
       String pluginName) {
-    final NamedProvider<T> item = new NamedProvider<T>(impl, pluginName);
+    final NamedProvider<T> item = new NamedProvider<>(impl, pluginName);
     NamedProvider<T> old = null;
     while (!ref.compareAndSet(old, item)) {
       old = ref.get();
@@ -216,7 +216,7 @@
 
     @Override
     public ReloadableHandle replace(Key<T> newKey, Provider<T> newItem) {
-      NamedProvider<T> n = new NamedProvider<T>(newItem, item.pluginName);
+      NamedProvider<T> n = new NamedProvider<>(newItem, item.pluginName);
       if (ref.compareAndSet(item, n)) {
         return new ReloadableHandle(newKey, n, defaultItem);
       }
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicItemProvider.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicItemProvider.java
index 1074ee5..9b09d15 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicItemProvider.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicItemProvider.java
@@ -37,7 +37,7 @@
   }
 
   public DynamicItem<T> get() {
-    return new DynamicItem<T>(key, find(injector, type), "gerrit");
+    return new DynamicItem<>(key, find(injector, type), "gerrit");
   }
 
   private static <T> Provider<T> find(Injector src, TypeLiteral<T> type) {
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicMap.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicMap.java
index 2d6098c..4251891 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicMap.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicMap.java
@@ -81,14 +81,14 @@
     Key<DynamicMap<T>> key = (Key<DynamicMap<T>>) Key.get(
         Types.newParameterizedType(DynamicMap.class, member.getType()));
     binder.bind(key)
-        .toProvider(new DynamicMapProvider<T>(member))
+        .toProvider(new DynamicMapProvider<>(member))
         .in(Scopes.SINGLETON);
   }
 
   final ConcurrentMap<NamePair, Provider<T>> items;
 
   DynamicMap() {
-    items = new ConcurrentHashMap<NamePair, Provider<T>>(
+    items = new ConcurrentHashMap<>(
         16 /* initial size */,
         0.75f /* load factor */,
         1 /* concurrency level of 1, load/unload is single threaded */);
@@ -115,7 +115,7 @@
    * @return sorted set of active plugins that supply at least one item.
    */
   public SortedSet<String> plugins() {
-    SortedSet<String> r = new TreeSet<String>();
+    SortedSet<String> r = new TreeSet<>();
     for (NamePair p : items.keySet()) {
       r.add(p.pluginName);
     }
@@ -129,7 +129,7 @@
    * @return items exported by a plugin, keyed by the export name.
    */
   public SortedMap<String, Provider<T>> byPlugin(String pluginName) {
-    SortedMap<String, Provider<T>> r = new TreeMap<String, Provider<T>>();
+    SortedMap<String, Provider<T>> r = new TreeMap<>();
     for (Map.Entry<NamePair, Provider<T>> e : items.entrySet()) {
       if (e.getKey().pluginName.equals(pluginName)) {
         r.put(e.getKey().exportName, e.getValue());
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicMapProvider.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicMapProvider.java
index c6e4701..2554673 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicMapProvider.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicMapProvider.java
@@ -34,7 +34,7 @@
 
   public DynamicMap<T> get() {
     PrivateInternals_DynamicMapImpl<T> m =
-        new PrivateInternals_DynamicMapImpl<T>();
+        new PrivateInternals_DynamicMapImpl<>();
     List<Binding<T>> bindings = injector.findBindingsByType(type);
     if (bindings != null) {
       for (Binding<T> b : bindings) {
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicSet.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicSet.java
index b2f19e5..628745a 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicSet.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicSet.java
@@ -72,7 +72,7 @@
     Key<DynamicSet<T>> key = (Key<DynamicSet<T>>) Key.get(
         Types.newParameterizedType(DynamicSet.class, member.getType()));
     binder.bind(key)
-      .toProvider(new DynamicSetProvider<T>(member))
+      .toProvider(new DynamicSetProvider<>(member))
       .in(Scopes.SINGLETON);
   }
 
@@ -136,7 +136,7 @@
   private final CopyOnWriteArrayList<AtomicReference<Provider<T>>> items;
 
   DynamicSet(Collection<AtomicReference<Provider<T>>> base) {
-    items = new CopyOnWriteArrayList<AtomicReference<Provider<T>>>(base);
+    items = new CopyOnWriteArrayList<>(base);
   }
 
   @Override
@@ -194,8 +194,7 @@
    * @return handle to remove the item at a later point in time.
    */
   public RegistrationHandle add(final Provider<T> item) {
-    final AtomicReference<Provider<T>> ref =
-        new AtomicReference<Provider<T>>(item);
+    final AtomicReference<Provider<T>> ref = new AtomicReference<>(item);
     items.add(ref);
     return new RegistrationHandle() {
       @Override
@@ -218,7 +217,7 @@
    *         without it ever leaving the collection.
    */
   public ReloadableRegistrationHandle<T> add(Key<T> key, Provider<T> item) {
-    AtomicReference<Provider<T>> ref = new AtomicReference<Provider<T>>(item);
+    AtomicReference<Provider<T>> ref = new AtomicReference<>(item);
     items.add(ref);
     return new ReloadableHandle(ref, key, item);
   }
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicSetProvider.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicSetProvider.java
index 21fa1b8..9ea96d4 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicSetProvider.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/DynamicSetProvider.java
@@ -36,7 +36,7 @@
   }
 
   public DynamicSet<T> get() {
-    return new DynamicSet<T>(find(injector, type));
+    return new DynamicSet<>(find(injector, type));
   }
 
   private static <T> List<AtomicReference<Provider<T>>> find(
@@ -47,16 +47,12 @@
     if (cnt == 0) {
       return Collections.emptyList();
     }
-    List<AtomicReference<Provider<T>>> r = newList(cnt);
+    List<AtomicReference<Provider<T>>> r = new ArrayList<>(cnt);
     for (Binding<T> b : bindings) {
       if (b.getKey().getAnnotation() != null) {
-        r.add(new AtomicReference<Provider<T>>(b.getProvider()));
+        r.add(new AtomicReference<>(b.getProvider()));
       }
     }
     return r;
   }
-
-  private static <T> List<AtomicReference<Provider<T>>> newList(int cnt) {
-    return new ArrayList<AtomicReference<Provider<T>>>(cnt);
-  }
 }
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/PrivateInternals_DynamicTypes.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/PrivateInternals_DynamicTypes.java
index 3742f47..96538e1 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/PrivateInternals_DynamicTypes.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/registration/PrivateInternals_DynamicTypes.java
@@ -31,7 +31,7 @@
 /** <b>DO NOT USE</b> */
 public class PrivateInternals_DynamicTypes {
   public static Map<TypeLiteral<?>, DynamicItem<?>> dynamicItemsOf(Injector src) {
-    Map<TypeLiteral<?>, DynamicItem<?>> m = newHashMap();
+    Map<TypeLiteral<?>, DynamicItem<?>> m = new HashMap<>();
     for (Map.Entry<Key<?>, Binding<?>> e : src.getBindings().entrySet()) {
       TypeLiteral<?> type = e.getKey().getTypeLiteral();
       if (type.getRawType() == DynamicItem.class) {
@@ -47,7 +47,7 @@
   }
 
   public static Map<TypeLiteral<?>, DynamicSet<?>> dynamicSetsOf(Injector src) {
-    Map<TypeLiteral<?>, DynamicSet<?>> m = newHashMap();
+    Map<TypeLiteral<?>, DynamicSet<?>> m = new HashMap<>();
     for (Map.Entry<Key<?>, Binding<?>> e : src.getBindings().entrySet()) {
       TypeLiteral<?> type = e.getKey().getTypeLiteral();
       if (type.getRawType() == DynamicSet.class) {
@@ -63,7 +63,7 @@
   }
 
   public static Map<TypeLiteral<?>, DynamicMap<?>> dynamicMapsOf(Injector src) {
-    Map<TypeLiteral<?>, DynamicMap<?>> m = newHashMap();
+    Map<TypeLiteral<?>, DynamicMap<?>> m = new HashMap<>();
     for (Map.Entry<Key<?>, Binding<?>> e : src.getBindings().entrySet()) {
       TypeLiteral<?> type = e.getKey().getTypeLiteral();
       if (type.getRawType() == DynamicMap.class) {
@@ -85,7 +85,7 @@
       return Collections.emptyList();
     }
 
-    List<RegistrationHandle> handles = new ArrayList<RegistrationHandle>(4);
+    List<RegistrationHandle> handles = new ArrayList<>(4);
     try {
       for (Map.Entry<TypeLiteral<?>, DynamicItem<?>> e : items.entrySet()) {
         @SuppressWarnings("unchecked")
@@ -115,7 +115,7 @@
       return Collections.emptyList();
     }
 
-    List<RegistrationHandle> handles = new ArrayList<RegistrationHandle>(4);
+    List<RegistrationHandle> handles = new ArrayList<>(4);
     try {
       for (Map.Entry<TypeLiteral<?>, DynamicSet<?>> e : sets.entrySet()) {
         @SuppressWarnings("unchecked")
@@ -148,7 +148,7 @@
       return Collections.emptyList();
     }
 
-    List<RegistrationHandle> handles = new ArrayList<RegistrationHandle>(4);
+    List<RegistrationHandle> handles = new ArrayList<>(4);
     try {
       for (Map.Entry<TypeLiteral<?>, DynamicMap<?>> e : maps.entrySet()) {
         @SuppressWarnings("unchecked")
@@ -183,7 +183,7 @@
 
       @Override
       public void start() {
-        handles = new ArrayList<RegistrationHandle>(4);
+        handles = new ArrayList<>(4);
         Injector parent = self.getParent();
         while (parent != null) {
           handles.addAll(attachSets(self, dynamicSetsOf(parent)));
@@ -211,10 +211,6 @@
     }
   }
 
-  private static <K,V> Map<K, V> newHashMap() {
-    return new HashMap<K,V>();
-  }
-
   private static <T> List<Binding<T>> bindings(Injector src, TypeLiteral<T> type) {
     return src.findBindingsByType(type);
   }
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/NotImplementedException.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/NotImplementedException.java
new file mode 100644
index 0000000..10d0a14
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/NotImplementedException.java
@@ -0,0 +1,24 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.extensions.restapi;
+
+/** Method is not implemented in currently used implementation. */
+public class NotImplementedException extends UnsupportedOperationException {
+  private static final long serialVersionUID = 1L;
+
+  public NotImplementedException() {
+    super("Not implemented.");
+  }
+}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/Response.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/Response.java
index 848004d..314c898 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/Response.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/Response.java
@@ -21,12 +21,12 @@
 
   /** HTTP 200 OK: pointless wrapper for type safety. */
   public static <T> Response<T> ok(T value) {
-    return new Impl<T>(200, value);
+    return new Impl<>(200, value);
   }
 
   /** HTTP 201 Created: typically used when a new resource is made. */
   public static <T> Response<T> created(T value) {
-    return new Impl<T>(201, value);
+    return new Impl<>(201, value);
   }
 
   /** HTTP 204 No Content: typically used when the resource is deleted. */
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/RestApiModule.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/RestApiModule.java
index b3a0e18..7708a5c 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/RestApiModule.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/RestApiModule.java
@@ -31,47 +31,47 @@
 
   protected <R extends RestResource>
   ReadViewBinder<R> get(TypeLiteral<RestView<R>> viewType) {
-    return new ReadViewBinder<R>(view(viewType, GET, "/"));
+    return new ReadViewBinder<>(view(viewType, GET, "/"));
   }
 
   protected <R extends RestResource>
   ModifyViewBinder<R> put(TypeLiteral<RestView<R>> viewType) {
-    return new ModifyViewBinder<R>(view(viewType, PUT, "/"));
+    return new ModifyViewBinder<>(view(viewType, PUT, "/"));
   }
 
   protected <R extends RestResource>
   ModifyViewBinder<R> post(TypeLiteral<RestView<R>> viewType) {
-    return new ModifyViewBinder<R>(view(viewType, POST, "/"));
+    return new ModifyViewBinder<>(view(viewType, POST, "/"));
   }
 
   protected <R extends RestResource>
   ModifyViewBinder<R> delete(TypeLiteral<RestView<R>> viewType) {
-    return new ModifyViewBinder<R>(view(viewType, DELETE, "/"));
+    return new ModifyViewBinder<>(view(viewType, DELETE, "/"));
   }
 
   protected <R extends RestResource>
   ReadViewBinder<R> get(TypeLiteral<RestView<R>> viewType, String name) {
-    return new ReadViewBinder<R>(view(viewType, GET, name));
+    return new ReadViewBinder<>(view(viewType, GET, name));
   }
 
   protected <R extends RestResource>
   ModifyViewBinder<R> put(TypeLiteral<RestView<R>> viewType, String name) {
-    return new ModifyViewBinder<R>(view(viewType, PUT, name));
+    return new ModifyViewBinder<>(view(viewType, PUT, name));
   }
 
   protected <R extends RestResource>
   ModifyViewBinder<R> post(TypeLiteral<RestView<R>> viewType, String name) {
-    return new ModifyViewBinder<R>(view(viewType, POST, name));
+    return new ModifyViewBinder<>(view(viewType, POST, name));
   }
 
   protected <R extends RestResource>
   ModifyViewBinder<R> delete(TypeLiteral<RestView<R>> viewType, String name) {
-    return new ModifyViewBinder<R>(view(viewType, DELETE, name));
+    return new ModifyViewBinder<>(view(viewType, DELETE, name));
   }
 
   protected <P extends RestResource>
   ChildCollectionBinder<P> child(TypeLiteral<RestView<P>> type, String name) {
-    return new ChildCollectionBinder<P>(view(type, GET, name));
+    return new ChildCollectionBinder<>(view(type, GET, name));
   }
 
   protected <R extends RestResource>
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/css/rebind/CssLinker.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/css/rebind/CssLinker.java
index 0f6992d..af80b3c 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/css/rebind/CssLinker.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/css/rebind/CssLinker.java
@@ -44,8 +44,7 @@
     final ArtifactSet returnTo = new ArtifactSet();
     int index = 0;
 
-    final HashMap<String, PublicResource> css =
-        new HashMap<String, PublicResource>();
+    final HashMap<String, PublicResource> css = new HashMap<>();
 
     for (final StandardStylesheetReference ssr : artifacts
         .<StandardStylesheetReference> find(StandardStylesheetReference.class)) {
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyCommand.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyCommand.java
index 15caa34..a0fee2b 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyCommand.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyCommand.java
@@ -74,6 +74,12 @@
       case KeyCodes.KEY_ESCAPE:
         namedKey(b, KeyConstants.I.keyEsc());
         break;
+      case KeyCodes.KEY_LEFT:
+        namedKey(b, KeyConstants.I.keyLeft());
+        break;
+      case KeyCodes.KEY_RIGHT:
+        namedKey(b, KeyConstants.I.keyRight());
+        break;
       default:
         b.openSpan();
         b.setStyleName(KeyResources.I.css().helpKey());
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyCommandSet.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyCommandSet.java
index 6600a18..e2fec27 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyCommandSet.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyCommandSet.java
@@ -35,7 +35,7 @@
   }
 
   public KeyCommandSet(final String setName) {
-    map = new HashMap<Integer, KeyCommand>();
+    map = new HashMap<>();
     name = setName;
   }
 
@@ -79,7 +79,7 @@
 
   public void add(final KeyCommandSet set) {
     if (sets == null) {
-      sets = new ArrayList<KeyCommandSet>();
+      sets = new ArrayList<>();
     }
     assert !sets.contains(set);
     sets.add(set);
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.java
index b4cb41e..d26ca8c 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.java
@@ -35,4 +35,6 @@
   String keyShift();
   String keyEnter();
   String keyEsc();
+  String keyLeft();
+  String keyRight();
 }
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.properties b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.properties
index 2e12b07..76a0318 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.properties
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.properties
@@ -13,3 +13,5 @@
 keyShift = Shift
 keyEnter = Enter
 keyEsc = Esc
+keyLeft = Left
+keyRight = Right
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyHelpPopup.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyHelpPopup.java
index 67a5ef4..c08e830 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyHelpPopup.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyHelpPopup.java
@@ -133,8 +133,7 @@
    *         the same name, so that each set name appears at most once.
    */
   private static Collection<KeyCommandSet> combinedSetsByName() {
-    final LinkedHashMap<String, KeyCommandSet> byName =
-        new LinkedHashMap<String, KeyCommandSet>();
+    LinkedHashMap<String, KeyCommandSet> byName = new LinkedHashMap<>();
     for (final KeyCommandSet set : GlobalKey.active.all.getSets()) {
       KeyCommandSet v = byName.get(set.getName());
       if (v == null) {
@@ -171,7 +170,7 @@
       lists.resizeRows(row + keys.size());
     }
 
-    Map<KeyCommand, Integer> rows = new HashMap<KeyCommand, Integer>();
+    Map<KeyCommand, Integer> rows = new HashMap<>();
     FORMAT_KEYS: for (int i = 0; i < keys.size(); i++) {
       final KeyCommand k = keys.get(i);
       if (rows.containsKey(k)) {
@@ -234,7 +233,7 @@
   }
 
   private List<KeyCommand> sort(final KeyCommandSet set) {
-    final List<KeyCommand> keys = new ArrayList<KeyCommand>(set.getKeys());
+    final List<KeyCommand> keys = new ArrayList<>(set.getKeys());
     Collections.sort(keys, new Comparator<KeyCommand>() {
       @Override
       public int compare(KeyCommand arg0, KeyCommand arg1) {
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/AttMap.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/AttMap.java
index 46d7f51..b08b29f 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/AttMap.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/AttMap.java
@@ -23,7 +23,7 @@
   private static final HashMap<String, Tag> TAGS;
   static {
     final Tag src = new SrcTag();
-    TAGS = new HashMap<String, Tag>();
+    TAGS = new HashMap<>();
     TAGS.put("a", new AnchorTag());
     TAGS.put("form", new FormTag());
     TAGS.put("img", src);
@@ -31,8 +31,8 @@
     TAGS.put("frame", src);
   }
 
-  private final ArrayList<String> names = new ArrayList<String>();
-  private final ArrayList<String> values = new ArrayList<String>();
+  private final ArrayList<String> names = new ArrayList<>();
+  private final ArrayList<String> values = new ArrayList<>();
 
   private Tag tag = ANY;
   private int live;
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/HighlightSuggestOracle.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/HighlightSuggestOracle.java
index ed4e6cb..216add1 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/HighlightSuggestOracle.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/HighlightSuggestOracle.java
@@ -45,7 +45,7 @@
           final Response response) {
         final String qpat = getQueryPattern(request.getQuery());
         final boolean html = isHTML();
-        final ArrayList<Suggestion> r = new ArrayList<Suggestion>();
+        final ArrayList<Suggestion> r = new ArrayList<>();
         for (final Suggestion s : response.getSuggestions()) {
           r.add(new BoldSuggestion(qpat, s, html));
         }
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/user/client/DialogVisibleEvent.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/user/client/DialogVisibleEvent.java
index 80a940a..74218b4 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/user/client/DialogVisibleEvent.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/user/client/DialogVisibleEvent.java
@@ -22,7 +22,7 @@
 
   public static Type<DialogVisibleHandler> getType() {
     if (TYPE == null) {
-      TYPE = new Type<DialogVisibleHandler>();
+      TYPE = new Type<>();
     }
     return TYPE;
   }
diff --git a/gerrit-gwtui/BUCK b/gerrit-gwtui/BUCK
index e978323..56c52bf 100644
--- a/gerrit-gwtui/BUCK
+++ b/gerrit-gwtui/BUCK
@@ -7,7 +7,7 @@
     'unzip -q $SRCDIR/ui_dbg.zip;' +
     'mv' +
     ' gerrit_ui/gerrit_ui.nocache.js' +
-    ' gerrit_ui/gerrit_dbg.nocache.js;' +
+    ' gerrit_ui/dbg_gerrit_ui.nocache.js;' +
     'unzip -qo $SRCDIR/ui_opt.zip;' +
     'mkdir -p $(dirname $OUT);' +
     'zip -qr $OUT .',
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
index 6db8180..dd9a28b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
@@ -689,6 +689,7 @@
       addDocLink(m, C.menuDocumentationUpload(), "user-upload.html");
       addDocLink(m, C.menuDocumentationAccess(), "access-control.html");
       addDocLink(m, C.menuDocumentationAPI(), "rest-api.html");
+      addDocLink(m, C.menuDocumentationProjectOwnerGuide(), "intro-project-owner.html");
       menuLeft.add(m, C.menuDocumentation());
     }
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java
index a93dda5..5ba520c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java
@@ -91,6 +91,7 @@
   String menuDocumentationUpload();
   String menuDocumentationAccess();
   String menuDocumentationAPI();
+  String menuDocumentationProjectOwnerGuide();
 
   String searchHint();
   String searchButton();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties
index 38498f3..58a6d08 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties
@@ -74,6 +74,7 @@
 menuDocumentationUpload = Uploading
 menuDocumentationAccess = Access Controls
 menuDocumentationAPI = REST API
+menuDocumentationProjectOwnerGuide = Project Owner Guide
 
 searchHint = Search term
 searchButton = Search
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/MessageOfTheDayBar.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/MessageOfTheDayBar.java
index fa569b8..b3d8c23 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/MessageOfTheDayBar.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/MessageOfTheDayBar.java
@@ -74,7 +74,7 @@
   }
 
   private static List<HostPageData.Message> filter(List<HostPageData.Message> in) {
-    List<HostPageData.Message> show = new ArrayList<HostPageData.Message>();
+    List<HostPageData.Message> show = new ArrayList<>();
     for (HostPageData.Message m : in) {
       if (Cookies.getCookie(cookieName(m)) == null) {
         show.add(m);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchSuggestOracle.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchSuggestOracle.java
index 3b6011b..10220e5 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchSuggestOracle.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchSuggestOracle.java
@@ -102,6 +102,7 @@
     suggestions.add("is:owner");
     suggestions.add("is:reviewer");
     suggestions.add("is:open");
+    suggestions.add("is:pending");
     suggestions.add("is:draft");
     suggestions.add("is:closed");
     suggestions.add("is:submitted");
@@ -111,6 +112,7 @@
 
     suggestions.add("status:");
     suggestions.add("status:open");
+    suggestions.add("status:pending");
     suggestions.add("status:reviewed");
     suggestions.add("status:submitted");
     suggestions.add("status:closed");
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/StringListPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/StringListPanel.java
index 618ee3e..bc36654 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/StringListPanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/StringListPanel.java
@@ -30,6 +30,7 @@
 import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;
 import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.FocusWidget;
+import com.google.gwt.user.client.ui.HasEnabled;
 import com.google.gwt.user.client.ui.HorizontalPanel;
 import com.google.gwt.user.client.ui.Image;
 import com.google.gwt.user.client.ui.ImageResourceRenderer;
@@ -38,9 +39,9 @@
 import java.util.ArrayList;
 import java.util.List;
 
-public class StringListPanel extends FlowPanel {
+public class StringListPanel extends FlowPanel implements HasEnabled {
   private final StringListTable t;
-  private final HorizontalPanel titlePanel;
+  private HorizontalPanel titlePanel;
   protected final HorizontalPanel buttonPanel;
   private final Button deleteButton;
   private Image info;
@@ -49,10 +50,12 @@
   public StringListPanel(String title, List<String> fieldNames, FocusWidget w,
       boolean autoSort) {
     widget = w;
-    titlePanel = new HorizontalPanel();
-    SmallHeading titleLabel = new SmallHeading(title);
-    titlePanel.add(titleLabel);
-    add(titlePanel);
+    if (title != null) {
+      titlePanel = new HorizontalPanel();
+      SmallHeading titleLabel = new SmallHeading(title);
+      titlePanel.add(titleLabel);
+      add(titlePanel);
+    }
 
     t = new StringListTable(fieldNames, autoSort);
     add(t);
@@ -77,25 +80,37 @@
   }
 
   public void setInfo(String msg) {
-    if (info == null) {
+    if (info == null && titlePanel != null) {
       info = new Image(Gerrit.RESOURCES.info());
       titlePanel.add(info);
     }
-    info.setTitle(msg);
+    if (info != null) {
+      info.setTitle(msg);
+    }
   }
 
   public List<List<String>> getValues() {
     return t.getValues();
   }
 
+  public List<String> getValues(int i) {
+    List<List<String>> allValuesList = getValues();
+    List<String> singleValueList = new ArrayList<>(allValuesList.size());
+    for (List<String> values : allValuesList) {
+      singleValueList.add(values.get(i));
+    }
+    return singleValueList;
+  }
+
   private class StringListTable extends NavigationTable<List<String>> {
+    private final Button addButton;
     private final List<NpTextBox> inputs;
     private final boolean autoSort;
 
     StringListTable(List<String> names, boolean autoSort) {
       this.autoSort = autoSort;
 
-      Button addButton =
+      addButton =
           new Button(new ImageResourceRenderer().render(Gerrit.RESOURCES.listAdd()));
       addButton.setTitle(Gerrit.C.stringListPanelAdd());
       OnEditEnabler e = new OnEditEnabler(addButton);
@@ -260,11 +275,8 @@
     void add() {
       List<String> values = new ArrayList<>();
       for (NpTextBox input : inputs) {
-        String v = input.getValue().trim();
-        if (!v.isEmpty()) {
-          input.setValue("");
-          values.add(v);
-        }
+        values.add(input.getValue().trim());
+        input.setValue("");
       }
       insert(values);
     }
@@ -315,5 +327,33 @@
     protected Object getRowItemKey(List<String> item) {
       return item.get(0);
     }
+
+    void setEnabled(boolean enabled) {
+      addButton.setVisible(enabled);
+      for (NpTextBox input : inputs) {
+        input.setEnabled(enabled);
+      }
+      for (int row = 2; row < table.getRowCount(); row++) {
+        table.getWidget(row, 0).setVisible(enabled);
+        if (!autoSort) {
+          table.getWidget(row, inputs.size() + 1).setVisible(enabled);
+          table.getWidget(row, inputs.size() + 2).setVisible(enabled);
+        }
+      }
+      if (enabled) {
+        updateNavigationLinks();
+      }
+    }
+  }
+
+  @Override
+  public boolean isEnabled() {
+    return deleteButton.isVisible();
+  }
+
+  @Override
+  public void setEnabled(boolean enabled) {
+    t.setEnabled(enabled);
+    deleteButton.setVisible(enabled);
   }
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.properties
index 749b5bf..f7760e3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.properties
@@ -11,7 +11,7 @@
 reversePatchSetOrder = Display Patch Sets In Reverse Order (deprecated: Old Change Screen)
 showUsernameInReviewCategory = Display Person Name In Review Category
 maximumPageSizeFieldLabel = Maximum Page Size:
-commentVisibilityLabel = Comment Visibility:
+commentVisibilityLabel = Comment Visibility (deprecated: Old Change Screen):
 changeScreenLabel = Change View:
 diffViewLabel = Diff View (New Change Screen):
 dateFormatLabel = Date/Time Format:
@@ -20,7 +20,9 @@
 showRelativeDateInChangeTable = Show Relative Dates In Changes Table
 showSizeBarInChangeTable = Show Change Sizes As Colored Bars In Changes Table
 myMenu = My Menu
-myMenuInfo = Menu Items for the 'My' top level menu.
+myMenuInfo = \
+  Menu items for the 'My' top level menu. \
+  The first menu item defines the default screen.
 myMenuName = Name
 myMenuUrl = URL
 myMenuReset = Reset
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java
index 9e87b48..a92b736 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java
@@ -137,4 +137,7 @@
 
   String pagedProjectListPrev();
   String pagedProjectListNext();
+
+  String pagedGroupListPrev();
+  String pagedGroupListNext();
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
index 04baf49..ef35e00 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
@@ -102,6 +102,9 @@
 pagedProjectListPrev = &#x21e6;Prev
 pagedProjectListNext = Next&#x21e8;
 
+pagedGroupListPrev = &#x21e6;Prev
+pagedGroupListNext = Next&#x21e8;
+
 addPermission = Add Permission ...
 
 # Permission Names
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupListScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupListScreen.java
index bed6b4a..6579f83 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupListScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupListScreen.java
@@ -21,8 +21,10 @@
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.client.ui.AccountScreen;
 import com.google.gerrit.client.ui.FilteredUserInterface;
+import com.google.gerrit.client.ui.Hyperlink;
 import com.google.gerrit.client.ui.IgnoreOutdatedFilterResultsCallbackWrapper;
 import com.google.gerrit.common.PageLinks;
+import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
 import com.google.gwt.event.dom.client.KeyCodes;
 import com.google.gwt.event.dom.client.KeyUpEvent;
 import com.google.gwt.event.dom.client.KeyUpHandler;
@@ -32,11 +34,16 @@
 import com.google.gwtexpui.globalkey.client.NpTextBox;
 
 public class GroupListScreen extends AccountScreen implements FilteredUserInterface {
+  private Hyperlink prev;
+  private Hyperlink next;
   private GroupTable groups;
   private NpTextBox filterTxt;
-  private String subname;
+  private String subname = "";
+  private int startPosition;
+  private int pageSize;
 
   public GroupListScreen() {
+    configurePageSize();
   }
 
   public GroupListScreen(String params) {
@@ -49,6 +56,22 @@
       if ("filter".equals(kv[0])) {
         subname = URL.decodeQueryString(kv[1]);
       }
+
+      if ("skip".equals(kv[0]) && URL.decodeQueryString(kv[1]).matches("^[\\d]+")) {
+        startPosition = Integer.parseInt(URL.decodeQueryString(kv[1]));
+      }
+    }
+    configurePageSize();
+  }
+
+  private void configurePageSize() {
+    if (Gerrit.isSignedIn()) {
+      final AccountGeneralPreferences p =
+          Gerrit.getUserAccount().getGeneralPreferences();
+      final short m = p.getMaximumPageSize();
+      pageSize = 0 < m ? m : AccountGeneralPreferences.DEFAULT_PAGESIZE;
+    } else {
+      pageSize = AccountGeneralPreferences.DEFAULT_PAGESIZE;
     }
   }
 
@@ -56,13 +79,17 @@
   protected void onLoad() {
     super.onLoad();
     display();
-    refresh(false);
+    refresh(false, false);
   }
 
-  private void refresh(final boolean open) {
-    setToken(subname == null || "".equals(subname) ? ADMIN_GROUPS
-        : ADMIN_GROUPS + "?filter=" + URL.encodeQueryString(subname));
-    GroupMap.match(subname,
+  private void refresh(final boolean open, final boolean filterModified) {
+    if (filterModified){
+      startPosition = 0;
+    }
+    setToken(getTokenForScreen(subname, startPosition));
+    // Retrieve one more group than page size to determine if there are more
+    // groups to display
+    GroupMap.match(subname, pageSize + 1, startPosition,
         new IgnoreOutdatedFilterResultsCallbackWrapper<GroupMap>(this,
             new GerritCallback<GroupMap>() {
               @Override
@@ -71,13 +98,45 @@
                   Gerrit.display(PageLinks.toGroup(
                       result.values().get(0).getGroupUUID()));
                 } else {
-                  groups.display(result, subname);
+                  if (result.size() <= pageSize) {
+                    groups.display(result, subname);
+                    next.setVisible(false);
+                  } else {
+                    groups.displaySubset(result, 0, result.size() - 1, subname);
+                    setupNavigationLink(next, subname, startPosition + pageSize);
+                  }
+                  if (startPosition > 0) {
+                    setupNavigationLink(prev, subname, startPosition - pageSize);
+                  } else {
+                    prev.setVisible(false);
+                  }
                   groups.finishDisplay();
                 }
               }
             }));
   }
 
+  private void setupNavigationLink(Hyperlink link, String filter, int skip) {
+    link.setTargetHistoryToken(getTokenForScreen(filter, skip));
+    link.setVisible(true);
+  }
+
+  private String getTokenForScreen(String filter, int skip) {
+    String token = ADMIN_GROUPS;
+    if (filter != null && !filter.isEmpty()) {
+      token += "?filter=" + URL.encodeQueryString(filter);
+    }
+    if (skip > 0) {
+      if (token.contains("?filter=")) {
+        token += ",";
+      } else {
+        token += "?";
+      }
+      token += "skip=" + skip;
+    }
+    return token;
+  }
+
   @Override
   public String getCurrentFilter() {
     return subname;
@@ -89,8 +148,20 @@
     setPageTitle(Util.C.groupListTitle());
     initPageHeader();
 
+    prev = new Hyperlink(Util.C.pagedGroupListPrev(), true, "");
+    prev.setVisible(false);
+
+    next = new Hyperlink(Util.C.pagedGroupListNext(), true, "");
+    next.setVisible(false);
+
     groups = new GroupTable(PageLinks.ADMIN_GROUPS);
     add(groups);
+
+    final HorizontalPanel buttons = new HorizontalPanel();
+    buttons.setStyleName(Gerrit.RESOURCES.css().changeTablePrevNextLinks());
+    buttons.add(prev);
+    buttons.add(next);
+    add(buttons);
   }
 
   private void initPageHeader() {
@@ -104,8 +175,13 @@
     filterTxt.addKeyUpHandler(new KeyUpHandler() {
       @Override
       public void onKeyUp(KeyUpEvent event) {
-        subname = filterTxt.getValue();
-        refresh(event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER);
+        boolean enterPressed =
+            event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER;
+        boolean filterModified = !filterTxt.getValue().equals(subname);
+        if (enterPressed || filterModified) {
+          subname = filterTxt.getValue();
+          refresh(enterPressed, filterModified);
+        }
       }
     });
     hp.add(filterTxt);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java
index de84081..1b420b4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java
@@ -95,6 +95,14 @@
   }
 
   public void display(List<GroupInfo> list, String toHighlight) {
+    displaySubset(list, toHighlight, 0, list.size());
+  }
+
+  public void displaySubset(GroupMap groups, int fromIndex, int toIndex, String toHighlight) {
+    displaySubset(Natives.asList(groups.values()), toHighlight, fromIndex, toIndex);
+  }
+
+  public void displaySubset(List<GroupInfo> list, String toHighlight, int fromIndex, int toIndex) {
     while (1 < table.getRowCount())
       table.removeRow(table.getRowCount() - 1);
 
@@ -104,7 +112,7 @@
         return a.name().compareTo(b.name());
       }
     });
-    for(GroupInfo group : list) {
+    for(GroupInfo group : list.subList(fromIndex, toIndex)) {
       final int row = table.getRowCount();
       table.insertRow(row);
       applyDataRowStyle(row);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionEditor.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionEditor.java
index efb2fb4..b3d8564 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionEditor.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionEditor.java
@@ -124,8 +124,8 @@
 
     PermissionNameRenderer nameRenderer =
         new PermissionNameRenderer(projectAccess.getCapabilities());
-    normalName = new ValueLabel<String>(nameRenderer);
-    deletedName = new ValueLabel<String>(nameRenderer);
+    normalName = new ValueLabel<>(nameRenderer);
+    deletedName = new ValueLabel<>(nameRenderer);
 
     initWidget(uiBinder.createAndBindUi(this));
     groupToAdd.setProject(projectName);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionRuleEditor.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionRuleEditor.java
index 07862f4..9e719ea 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionRuleEditor.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionRuleEditor.java
@@ -101,7 +101,7 @@
       Permission permission,
       PermissionRange.WithDefaults validRange) {
     this.groupInfo = groupInfo;
-    action = new ValueListBox<PermissionRule.Action>(actionRenderer);
+    action = new ValueListBox<>(actionRenderer);
 
     if (validRange != null && 10 < validRange.getRangeSize()) {
         min = new RangeBox.Box();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java
index 29a0bdb..14404f7 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java
@@ -15,6 +15,7 @@
 package com.google.gerrit.client.admin;
 
 import com.google.gerrit.client.Gerrit;
+import com.google.gerrit.client.StringListPanel;
 import com.google.gerrit.client.access.AccessMap;
 import com.google.gerrit.client.access.ProjectAccessInfo;
 import com.google.gerrit.client.actions.ActionButton;
@@ -47,7 +48,7 @@
 import com.google.gwt.user.client.ui.CheckBox;
 import com.google.gwt.user.client.ui.FlexTable;
 import com.google.gwt.user.client.ui.FlowPanel;
-import com.google.gwt.user.client.ui.FocusWidget;
+import com.google.gwt.user.client.ui.HasEnabled;
 import com.google.gwt.user.client.ui.HorizontalPanel;
 import com.google.gwt.user.client.ui.Image;
 import com.google.gwt.user.client.ui.Label;
@@ -59,7 +60,10 @@
 import com.google.gwtexpui.globalkey.client.NpTextArea;
 import com.google.gwtexpui.globalkey.client.NpTextBox;
 
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
@@ -77,7 +81,7 @@
   private ListBox contentMerge;
   private NpTextBox maxObjectSizeLimit;
   private Label effectiveMaxObjectSizeLimit;
-  private Map<String, Map<String, FocusWidget>> pluginConfigWidgets;
+  private Map<String, Map<String, HasEnabled>> pluginConfigWidgets;
 
   // Section: Contributor Agreements
   private ListBox contributorAgreements;
@@ -160,8 +164,8 @@
     maxObjectSizeLimit.setEnabled(isOwner);
 
     if (pluginConfigWidgets != null) {
-      for (Map<String, FocusWidget> widgetMap : pluginConfigWidgets.values()) {
-        for (FocusWidget widget : widgetMap.values()) {
+      for (Map<String, HasEnabled> widgetMap : pluginConfigWidgets.values()) {
+        for (HasEnabled widget : widgetMap.values()) {
           widget.setEnabled(isOwner);
         }
       }
@@ -185,6 +189,13 @@
   private void initProjectOptions() {
     grid.addHeader(new SmallHeading(Util.C.headingProjectOptions()));
 
+    state = new ListBox();
+    for (ProjectState stateValue : ProjectState.values()) {
+      state.addItem(Util.toLongString(stateValue), stateValue.name());
+    }
+    saveEnabler.listenTo(state);
+    grid.add(Util.C.headingProjectState(), state);
+
     submitType = new ListBox();
     for (final SubmitType type : SubmitType.values()) {
       submitType.addItem(Util.toLongString(type), type.name());
@@ -198,13 +209,6 @@
     saveEnabler.listenTo(submitType);
     grid.add(Util.C.headingProjectSubmitType(), submitType);
 
-    state = new ListBox();
-    for (final ProjectState stateValue : ProjectState.values()) {
-      state.addItem(Util.toLongString(stateValue), stateValue.name());
-    }
-    saveEnabler.listenTo(state);
-    grid.add(Util.C.headingProjectState(), state);
-
     contentMerge = newInheritedBooleanBox();
     saveEnabler.listenTo(contentMerge);
     grid.add(Util.C.useContentMerge(), contentMerge);
@@ -358,7 +362,7 @@
     pluginConfigWidgets = new HashMap<>();
 
     for (String pluginName : info.pluginConfig().keySet()) {
-      Map<String, FocusWidget> widgetMap = new HashMap<>();
+      Map<String, HasEnabled> widgetMap = new HashMap<>();
       pluginConfigWidgets.put(pluginName, widgetMap);
       LabeledWidgetsGrid g = new LabeledWidgetsGrid();
       g.addHeader(new SmallHeading(Util.M.pluginProjectOptionsTitle(pluginName)));
@@ -367,7 +371,7 @@
           info.pluginConfig(pluginName);
       pluginConfig.copyKeysIntoChildren("name");
       for (ConfigParameterInfo param : Natives.asList(pluginConfig.values())) {
-        FocusWidget w;
+        HasEnabled w;
         switch (param.type()) {
           case "STRING":
           case "INT":
@@ -381,7 +385,7 @@
             w = renderListBox(g, param);
             break;
           case "ARRAY":
-            w = renderTextArea(g, param);
+            w = renderStringListPanel(g, param);
             break;
           default:
             throw new UnsupportedOperationException("unsupported widget type");
@@ -498,24 +502,21 @@
     return listBox;
   }
 
-  private NpTextArea renderTextArea(LabeledWidgetsGrid g,
+  private StringListPanel renderStringListPanel(LabeledWidgetsGrid g,
       ConfigParameterInfo param) {
-    NpTextArea txtArea = new NpTextArea();
-    txtArea.setVisibleLines(4);
-    txtArea.setCharacterWidth(40);
-    StringBuilder sb = new StringBuilder();
-    for (int i = 0; i < param.values().length(); i++) {
-      String v = param.values().get(i);
-      sb.append(v).append("\n");
+    StringListPanel p =
+        new StringListPanel(null, Arrays.asList(getDisplayName(param)),
+            saveProject, false);
+    List<List<String>> values = new ArrayList<>();
+    for (String v : Natives.asList(param.values())) {
+      values.add(Arrays.asList(v));
     }
-    txtArea.setText(sb.toString());
-    if (param.editable()) {
-      saveEnabler.listenTo(txtArea);
-    } else {
-      txtArea.setEnabled(false);
+    p.display(values);
+    if (!param.editable()) {
+      p.setEnabled(false);
     }
-    addWidget(g, txtArea, param);
-    return txtArea;
+    addWidget(g, p, param);
+    return p;
   }
 
   private void addWidget(LabeledWidgetsGrid g, Widget w, ConfigParameterInfo param) {
@@ -590,11 +591,11 @@
   private Map<String, Map<String, ConfigParameterValue>> getPluginConfigValues() {
     Map<String, Map<String, ConfigParameterValue>> pluginConfigValues =
         new HashMap<>(pluginConfigWidgets.size());
-    for (Entry<String, Map<String, FocusWidget>> e : pluginConfigWidgets.entrySet()) {
+    for (Entry<String, Map<String, HasEnabled>> e : pluginConfigWidgets.entrySet()) {
       Map<String, ConfigParameterValue> values = new HashMap<>(e.getValue().size());
       pluginConfigValues.put(e.getKey(), values);
-      for (Entry<String, FocusWidget> e2 : e.getValue().entrySet()) {
-        FocusWidget widget = e2.getValue();
+      for (Entry<String, HasEnabled> e2 : e.getValue().entrySet()) {
+        HasEnabled widget = e2.getValue();
         if (widget instanceof TextBox) {
           values.put(e2.getKey(), ConfigParameterValue.create()
               .value(((TextBox) widget).getValue().trim()));
@@ -609,10 +610,11 @@
               ? listBox.getValue(listBox.getSelectedIndex()) : null;
           values.put(e2.getKey(), ConfigParameterValue.create()
               .value(value));
-        } else if (widget instanceof NpTextArea) {
-          String text = ((NpTextArea) widget).getText().trim();
-          values.put(e2.getKey(), ConfigParameterValue.create()
-              .values(text.split("\n")));
+        } else if (widget instanceof StringListPanel) {
+          values.put(e2.getKey(),
+              ConfigParameterValue.create().values(
+                  ((StringListPanel) widget).getValues(0)
+                      .toArray(new String[] {})));
         } else {
           throw new UnsupportedOperationException("unsupported widget type");
         }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/RangeBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/RangeBox.java
index bf04b07..088899e 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/RangeBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/RangeBox.java
@@ -49,7 +49,7 @@
     final ValueListBox<Integer> list;
 
     List() {
-      list = new ValueListBox<Integer>(rangeRenderer);
+      list = new ValueListBox<>(rangeRenderer);
       initWidget(list);
     }
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ActionContext.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ActionContext.java
index 8f701a3..7490d82 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ActionContext.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ActionContext.java
@@ -38,6 +38,7 @@
     Gerrit.ActionContext.prototype = {
       go: Gerrit.go,
       refresh: Gerrit.refresh,
+      refreshMenuBar: Gerrit.refreshMenuBar,
       showError: Gerrit.showError,
 
       br: function(){return doc.createElement('br')},
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ApiGlue.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ApiGlue.java
index ba7e6e6..8da896e 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ApiGlue.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ApiGlue.java
@@ -63,6 +63,7 @@
 
       go: @com.google.gerrit.client.api.ApiGlue::go(Ljava/lang/String;),
       refresh: @com.google.gerrit.client.api.ApiGlue::refresh(),
+      refreshMenuBar: @com.google.gerrit.client.api.ApiGlue::refreshMenuBar(),
       showError: @com.google.gerrit.client.api.ApiGlue::showError(Ljava/lang/String;),
 
       on: function (e,f){(this.events[e] || (this.events[e]=[])).push(f)},
@@ -191,6 +192,10 @@
     Gerrit.display(History.getToken());
   }
 
+  private static final void refreshMenuBar() {
+    Gerrit.refreshMenuBar();
+  }
+
   private static final void showError(String message) {
     new ErrorDialog(message).center();
   }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/Plugin.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/Plugin.java
index 00c674f..7ef022a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/Plugin.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/Plugin.java
@@ -52,6 +52,7 @@
       getPluginName: function(){return this.name},
       go: @com.google.gerrit.client.api.ApiGlue::go(Ljava/lang/String;),
       refresh: @com.google.gerrit.client.api.ApiGlue::refresh(),
+      refreshMenuBar: @com.google.gerrit.client.api.ApiGlue::refreshMenuBar(),
       showError: @com.google.gerrit.client.api.ApiGlue::showError(Ljava/lang/String;),
       on: function(e,f){G.on(e,f)},
       onAction: function(t,n,c){G._onAction(this.name,t,n,c)},
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.java
index 538cb63..b6fdd32 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.java
@@ -43,6 +43,7 @@
 import com.google.gerrit.client.ui.BranchLink;
 import com.google.gerrit.client.ui.ChangeLink;
 import com.google.gerrit.client.ui.CommentLinkProcessor;
+import com.google.gerrit.client.ui.Hyperlink;
 import com.google.gerrit.client.ui.InlineHyperlink;
 import com.google.gerrit.client.ui.Screen;
 import com.google.gerrit.client.ui.UserActivityMonitor;
@@ -55,6 +56,7 @@
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.core.client.JsArray;
 import com.google.gwt.core.client.JsArrayString;
+import com.google.gwt.dom.client.AnchorElement;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.NativeEvent;
 import com.google.gwt.dom.client.SelectElement;
@@ -69,6 +71,7 @@
 import com.google.gwt.uibinder.client.UiField;
 import com.google.gwt.uibinder.client.UiHandler;
 import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.EventListener;
 import com.google.gwt.user.client.rpc.AsyncCallback;
 import com.google.gwt.user.client.ui.Anchor;
@@ -139,7 +142,8 @@
   @UiField InlineHyperlink ownerLink;
   @UiField Element statusText;
   @UiField Image projectSettings;
-  @UiField InlineHyperlink projectLink;
+  @UiField AnchorElement projectSettingsLink;
+  @UiField InlineHyperlink projectDashboard;
   @UiField InlineHyperlink branchLink;
   @UiField Element strategy;
   @UiField Element submitActionText;
@@ -356,15 +360,20 @@
   }
 
   private void initProjectLinks(final ChangeInfo info) {
+    projectSettingsLink.setHref(
+        "#" + PageLinks.toProject(info.project_name_key()));
     projectSettings.addDomHandler(new ClickHandler() {
       @Override
       public void onClick(ClickEvent event) {
-        Gerrit.display(
-            PageLinks.toProject(info.project_name_key()));
+        if (Hyperlink.impl.handleAsClick((Event) event.getNativeEvent())) {
+          event.stopPropagation();
+          event.preventDefault();
+          Gerrit.display(PageLinks.toProject(info.project_name_key()));
+        }
       }
     }, ClickEvent.getType());
-    projectLink.setText(info.project());
-    projectLink.setTargetHistoryToken(
+    projectDashboard.setText(info.project());
+    projectDashboard.setTargetHistoryToken(
         PageLinks.toProjectDefaultDashboard(info.project_name_key()));
   }
 
@@ -791,7 +800,7 @@
     if (Gerrit.isSignedIn()) {
       initEditMessageAction(info, revision);
       replyAction = new ReplyAction(info, revision,
-          style, commentLinkProcessor, reply);
+          style, commentLinkProcessor, reply, quickApprove);
       if (topic.canEdit()) {
         keysAction.add(new KeyCommand(0, 't', Util.C.keyEditTopic()) {
           @Override
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.ui.xml
index 92d32ff..e0e6053 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.ui.xml
@@ -382,17 +382,19 @@
             </tr>
             <tr>
               <th><ui:msg>Project</ui:msg></th>
-              <td><x:InlineHyperlink ui:field='projectLink'
-                     title='Search for changes on this project'>
+              <td><x:InlineHyperlink ui:field='projectDashboard'
+                     title='Go to project dashboard'>
                      <ui:attribute name='title'/>
                   </x:InlineHyperlink>
-                  <g:Image
-                     ui:field='projectSettings'
-                     resource='{ico.gear}'
-                     styleName='{style.projectSettings}'
-                     title='Go to project'>
-                    <ui:attribute name='title'/>
-                  </g:Image>
+                  <a ui:field='projectSettingsLink'
+                     class='{style.projectSettings}'>
+                    <g:Image
+                       ui:field='projectSettings'
+                       resource='{ico.gear}'
+                       title='Go to project settings'>
+                      <ui:attribute name='title'/>
+                    </g:Image>
+                  </a>
               </td>
             </tr>
             <tr>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/EditMessageBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/EditMessageBox.java
index 11fc245..700638a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/EditMessageBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/EditMessageBox.java
@@ -55,6 +55,7 @@
     this.revision = revision;
     this.originalMessage = msg.trim();
     initWidget(uiBinder.createAndBindUi(this));
+    message.setText("");
     new TextBoxChangeListener(message) {
       public void onTextChanged(String newText) {
         save.setEnabled(!newText.trim()
@@ -65,8 +66,10 @@
 
   @Override
   protected void onLoad() {
-    message.setText(originalMessage);
-    save.setEnabled(false);
+    if (message.getText().isEmpty()) {
+      message.setText(originalMessage);
+      save.setEnabled(false);
+    }
     Scheduler.get().scheduleDeferred(new ScheduledCommand() {
       @Override
       public void execute() {
@@ -89,6 +92,7 @@
 
   @UiHandler("cancel")
   void onCancel(ClickEvent e) {
+    message.setText("");
     hide();
   }
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/QuickApprove.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/QuickApprove.java
index 98d495a..6e86730 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/QuickApprove.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/QuickApprove.java
@@ -109,16 +109,17 @@
 
   @Override
   public void onClick(ClickEvent event) {
-    if (replyAction != null) {
-      input.message(replyAction.getMessage());
+    if (replyAction != null && replyAction.isVisible()) {
+      replyAction.quickApprove(input);
+    } else {
+      ChangeApi.revision(changeId.get(), revision)
+        .view("review")
+        .post(input, new GerritCallback<ReviewInput>() {
+          @Override
+          public void onSuccess(ReviewInput result) {
+            Gerrit.display(PageLinks.toChange(changeId));
+          }
+        });
     }
-    ChangeApi.revision(changeId.get(), revision)
-      .view("review")
-      .post(input, new GerritCallback<ReviewInput>() {
-        @Override
-        public void onSuccess(ReviewInput result) {
-          Gerrit.display(PageLinks.toChange(changeId));
-        }
-      });
   }
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyAction.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyAction.java
index aaa301c..b234fe3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyAction.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyAction.java
@@ -17,6 +17,7 @@
 import com.google.gerrit.client.changes.ChangeInfo;
 import com.google.gerrit.client.changes.ChangeInfo.LabelInfo;
 import com.google.gerrit.client.changes.ChangeInfo.MessageInfo;
+import com.google.gerrit.client.changes.ReviewInput;
 import com.google.gerrit.client.rpc.NativeMap;
 import com.google.gerrit.client.ui.CommentLinkProcessor;
 import com.google.gerrit.reviewdb.client.PatchSet;
@@ -35,6 +36,7 @@
   private final ChangeScreen2.Style style;
   private final CommentLinkProcessor clp;
   private final Widget replyButton;
+  private final Widget quickApproveButton;
 
   private NativeMap<LabelInfo> allLabels;
   private NativeMap<JsArrayString> permittedLabels;
@@ -47,7 +49,8 @@
       String revision,
       ChangeScreen2.Style style,
       CommentLinkProcessor clp,
-      Widget replyButton) {
+      Widget replyButton,
+      Widget quickApproveButton) {
     this.psId = new PatchSet.Id(
         info.legacy_id(),
         info.revisions().get(revision)._number());
@@ -55,6 +58,7 @@
     this.style = style;
     this.clp = clp;
     this.replyButton = replyButton;
+    this.quickApproveButton = quickApproveButton;
 
     boolean current = revision.equals(info.current_revision());
     allLabels = info.all_labels();
@@ -63,8 +67,12 @@
         : NativeMap.<JsArrayString> create();
   }
 
-  String getMessage() {
-    return replyBox != null ? replyBox.getMessage() : null;
+  boolean isVisible() {
+    return popup != null;
+  }
+
+  void quickApprove(ReviewInput input) {
+    replyBox.quickApprove(input);
   }
 
   void hide() {
@@ -96,9 +104,8 @@
 
     final PluginSafePopupPanel p = new PluginSafePopupPanel(true, false);
     p.setStyleName(style.replyBox());
-    p.setGlassEnabled(true);
-    p.setGlassStyleName("");
     p.addAutoHidePartner(replyButton.getElement());
+    p.addAutoHidePartner(quickApproveButton.getElement());
     p.addCloseHandler(new CloseHandler<PopupPanel>() {
       @Override
       public void onClose(CloseEvent<PopupPanel> event) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyBox.java
index 64dcd28..4e77041 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ReplyBox.java
@@ -199,7 +199,16 @@
 
   @UiHandler("post")
   void onPost(ClickEvent e) {
-    in.message(getMessage());
+    postReview();
+  }
+
+  void quickApprove(ReviewInput quickApproveInput) {
+    in.mergeLabels(quickApproveInput);
+    postReview();
+  }
+
+  private void postReview() {
+    in.message(message.getText().trim());
     in.prePost();
     ChangeApi.revision(psId.getParentKey().get(), revision)
       .view("review")
@@ -214,12 +223,9 @@
     hide();
   }
 
-  String getMessage() {
-    return message.getText().trim();
-  }
-
   @UiHandler("cancel")
   void onCancel(ClickEvent e) {
+    message.setText("");
     hide();
   }
 
@@ -316,10 +322,23 @@
     }
   }
 
+  private Short normalizeDefaultValue(Short defaultValue, Set<Short> permittedValues) {
+    Short pmin = Collections.min(permittedValues);
+    Short pmax = Collections.max(permittedValues);
+    Short dv = defaultValue;
+    if (dv > pmax) {
+      dv = pmax;
+    } else if (dv < pmin) {
+      dv = pmin;
+    }
+    return dv;
+  }
+
   private void renderRadio(int row,
       List<Short> columns,
       LabelAndValues lv) {
     String id = lv.info.name();
+    Short dv = normalizeDefaultValue(lv.info.defaultValue(), lv.permitted);
 
     labelHelpColumn = 1 + columns.size();
     labelsTable.setText(row, 0, id);
@@ -339,9 +358,10 @@
       if (lv.permitted.contains(v)) {
         String text = lv.info.value_text(LabelValue.formatValue(v));
         LabelRadioButton b = new LabelRadioButton(group, text, v);
-        if ((self != null && v == self.value()) || (self == null && v == 0)) {
+        if ((self != null && v == self.value()) || (self == null && v.equals(dv))) {
           b.setValue(true);
           group.select(b);
+          in.label(group.label, v);
           labelsTable.setText(row, labelHelpColumn, b.text);
         }
         group.buttons.add(b);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Topic.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Topic.java
index e9f07c1..512203a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Topic.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Topic.java
@@ -18,7 +18,6 @@
 import com.google.gerrit.client.changes.ChangeApi;
 import com.google.gerrit.client.changes.ChangeInfo;
 import com.google.gerrit.client.rpc.GerritCallback;
-import com.google.gerrit.client.ui.BranchLink;
 import com.google.gerrit.client.ui.InlineHyperlink;
 import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.reviewdb.client.PatchSet;
@@ -84,14 +83,12 @@
   }
 
   private void initTopicLink(ChangeInfo info) {
-    text.setText(info.topic());
-    text.setTargetHistoryToken(
-        PageLinks.toChangeQuery(
-            BranchLink.query(
-                info.project_name_key(),
-                info.status(),
-                info.branch(),
-                info.topic())));
+    if (info.topic() != null && !info.topic().isEmpty()) {
+      text.setText(info.topic());
+      text.setTargetHistoryToken(
+          PageLinks.toChangeQuery(
+              PageLinks.op("topic", info.topic())));
+    }
   }
 
   boolean canEdit() {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Topic.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Topic.ui.xml
index 4031ba9..ae46b10 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Topic.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Topic.ui.xml
@@ -32,7 +32,7 @@
       <g:Image ui:field='editIcon'
           resource='{ico.edit}'
           styleName='{style.edit}'
-          title='Click to edit topic (Shortcut: t)'/>
+          title='Edit topic (Shortcut: t)'/>
     </div>
 
     <div ui:field='form' style='display: none' aria-hidden='true'>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeDetailCache.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeDetailCache.java
index b23403b..f2c97c1 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeDetailCache.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeDetailCache.java
@@ -84,7 +84,7 @@
     r.setCanRebase(can(rev.actions(), "rebase"));
     r.setCanRestore(can(info.actions(), "restore"));
     r.setCanRevert(can(info.actions(), "revert"));
-    r.setCanDeleteDraft(can(rev.actions(), "/"));
+    r.setCanDeleteDraft(can(info.actions(), "/"));
     r.setCanEditTopicName(can(info.actions(), "topic"));
     r.setCanSubmit(can(rev.actions(), "submit"));
     r.setCanEdit(true);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java
index c1cbc6a..0c1815f 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java
@@ -162,6 +162,7 @@
 
     public final native boolean optional() /*-{ return this.optional ? true : false; }-*/;
     public final native boolean blocking() /*-{ return this.blocking ? true : false; }-*/;
+    public final native short defaultValue() /*-{ return this.default_value; }-*/;
     final native short _value()
     /*-{
       if (this.value) return this.value;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeScreen.java
index 9d9078d..aa01ef2 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeScreen.java
@@ -300,7 +300,7 @@
       CallbackGroup cbs1 = new CallbackGroup();
       final CallbackGroup cbs2 = new CallbackGroup();
       final PatchSet.Id psId = event.getValue().getCurrentPatchSet().getId();
-      final Map<String, Patch> patches = new HashMap<String, Patch>();
+      final Map<String, Patch> patches = new HashMap<>();
       String revId =
           event.getValue().getCurrentPatchSetDetail().getInfo().getRevId();
 
@@ -330,7 +330,7 @@
 
               private void dependsOn(RelatedChanges.RelatedInfo info) {
                 ChangeAndCommit self = null;
-                Map<String, ChangeAndCommit> m = new HashMap<String, ChangeAndCommit>();
+                Map<String, ChangeAndCommit> m = new HashMap<>();
                 for (int i = 0; i < info.changes().length(); i++) {
                   ChangeAndCommit c = info.changes().get(i);
                   if (changeId.equals(c.legacy_id())) {
@@ -342,7 +342,7 @@
                 }
                 if (self != null && self.commit() != null
                     && self.commit().parents() != null) {
-                  List<ChangeInfo> d = new ArrayList<ChangeInfo>();
+                  List<ChangeInfo> d = new ArrayList<>();
                   for (CommitInfo p : Natives.asList(self.commit().parents())) {
                     ChangeAndCommit pc = m.get(p.commit());
                     if (pc != null && pc.has_change_number()) {
@@ -356,12 +356,12 @@
               }
 
               private void neededBy(RelatedChanges.RelatedInfo info) {
-                Set<String> mine = new HashSet<String>();
+                Set<String> mine = new HashSet<>();
                 for (PatchSet ps : event.getValue().getPatchSets()) {
                   mine.add(ps.getRevision().get());
                 }
 
-                List<ChangeInfo> n = new ArrayList<ChangeInfo>();
+                List<ChangeInfo> n = new ArrayList<>();
                 for (int i = 0; i < info.changes().length(); i++) {
                   ChangeAndCommit c = info.changes().get(i);
                   if (c.has_change_number()
@@ -418,7 +418,7 @@
               }
               public void onFailure(Throwable caught) {}
             }));
-        final Set<PatchSet.Id> withDrafts = new HashSet<PatchSet.Id>();
+        final Set<PatchSet.Id> withDrafts = new HashSet<>();
         event.getValue().setPatchSetsWithDraftComments(withDrafts);
         for (PatchSet ps : event.getValue().getPatchSets()) {
           if (!ps.getId().equals(psId)) {
@@ -478,7 +478,7 @@
             public void onSuccess(NativeMap<FileInfo> result) {
               JsArray<FileInfo> fileInfos = result.values();
               FileInfo.sortFileInfoByPath(fileInfos);
-              List<Patch> list = new ArrayList<Patch>(fileInfos.length());
+              List<Patch> list = new ArrayList<>(fileInfos.length());
               for (FileInfo f : Natives.asList(fileInfos)) {
                 Patch p = patches.get(f.path());
                 if (p == null) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable.java
index 3a65d20..571e742 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable.java
@@ -59,7 +59,7 @@
       keysAction.add(new StarKeyCommand(0, 's', Util.C.changeTableStar()));
     }
 
-    sections = new ArrayList<Section>();
+    sections = new ArrayList<>();
     table.setText(0, C_STAR, "");
     table.setText(0, C_SUBJECT, Util.C.changeTableColumnSubject());
     table.setText(0, C_OWNER, Util.C.changeTableColumnOwner());
@@ -308,7 +308,7 @@
           parent.insertNoneRow(dataBegin);
         }
       } else {
-        Set<Change.Id> cids = new HashSet<Change.Id>();
+        Set<Change.Id> cids = new HashSet<>();
 
         if (!hadData) {
           parent.removeRow(dataBegin);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CustomDashboardScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CustomDashboardScreen.java
index 840ebaa..320976e 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CustomDashboardScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CustomDashboardScreen.java
@@ -26,12 +26,7 @@
 
   @Override
   protected void onInitUI() {
-    table = new DashboardTable(params) {
-      @Override
-      protected void onLoad() {
-        super.onLoad();
-      }
-
+    table = new DashboardTable(this, params) {
       @Override
       public void finishDisplay() {
         super.finishDisplay();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/DashboardTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/DashboardTable.java
index ac68722..978d4e5 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/DashboardTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/DashboardTable.java
@@ -18,10 +18,13 @@
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.client.rpc.Natives;
 import com.google.gerrit.client.ui.InlineHyperlink;
+import com.google.gerrit.client.ui.Screen;
 import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.extensions.common.ListChangesOption;
 import com.google.gwt.core.client.JsArray;
+import com.google.gwt.event.dom.client.KeyPressEvent;
 import com.google.gwt.http.client.URL;
+import com.google.gwtexpui.globalkey.client.KeyCommand;
 
 import java.util.ArrayList;
 import java.util.EnumSet;
@@ -34,7 +37,7 @@
   private List<String> titles;
   private List<String> queries;
 
-  public DashboardTable(String params) {
+  public DashboardTable(final Screen screen, String params) {
     titles = new ArrayList<>();
     queries = new ArrayList<>();
     String foreach = null;
@@ -72,6 +75,13 @@
       addSection(s);
       sections.add(s);
     }
+
+    keysNavigation.add(new KeyCommand(0, 'R', Util.C.keyReloadSearch()) {
+      @Override
+      public void onKeyPress(KeyPressEvent event) {
+        Gerrit.display(screen.getToken());
+      }
+    });
   }
 
   private String removeLimit(String query) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetComplexDisclosurePanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetComplexDisclosurePanel.java
index 31685e4..b7a0ec8 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetComplexDisclosurePanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetComplexDisclosurePanel.java
@@ -76,7 +76,7 @@
   private Grid infoTable;
   private Panel actionsPanel;
   private PatchTable patchTable;
-  private final Set<ClickHandler> registeredClickHandler =  new HashSet<ClickHandler>();
+  private final Set<ClickHandler> registeredClickHandler =  new HashSet<>();
 
   private PatchSet.Id diffBaseId;
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetsBlock.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetsBlock.java
index 4805185..01c8fdb 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetsBlock.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetsBlock.java
@@ -44,7 +44,7 @@
  */
 public class PatchSetsBlock extends Composite {
   private final Map<PatchSet.Id, PatchSetComplexDisclosurePanel> patchSetPanels =
-      new HashMap<PatchSet.Id, PatchSetComplexDisclosurePanel>();
+      new HashMap<>();
 
   private final FlowPanel body;
   private HandlerRegistration regNavigation;
@@ -84,7 +84,7 @@
       }
     }
 
-    patchSetPanelsList = new ArrayList<PatchSetComplexDisclosurePanel>();
+    patchSetPanelsList = new ArrayList<>();
 
     for (final PatchSet ps : patchSets) {
       final PatchSetComplexDisclosurePanel p =
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchTable.java
index b89d1cc..425309d 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchTable.java
@@ -105,7 +105,7 @@
 
   private Map<Key, Integer> patchMap() {
     if (patchMap == null) {
-      patchMap = new HashMap<Patch.Key, Integer>();
+      patchMap = new HashMap<>();
       for (int i = 0; i < patchList.size(); i++) {
         patchMap.put(patchList.get(i).getKey(), i);
       }
@@ -154,7 +154,7 @@
       myTable.addClickHandler(clickHandler);
     } else {
       if (clickHandlers == null) {
-        clickHandlers = new ArrayList<ClickHandler>(2);
+        clickHandlers = new ArrayList<>(2);
       }
       clickHandlers.add(clickHandler);
     }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ProjectDashboardScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ProjectDashboardScreen.java
index 899e86b..d2eec27 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ProjectDashboardScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ProjectDashboardScreen.java
@@ -32,12 +32,7 @@
 
   @Override
   protected void onInitUI() {
-    table = new DashboardTable(params) {
-      @Override
-      protected void onLoad() {
-        super.onLoad();
-      }
-
+    table = new DashboardTable(this, params) {
       @Override
       public void finishDisplay() {
         super.finishDisplay();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PublishCommentScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PublishCommentScreen.java
index 10b7ac7..f718b5d 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PublishCommentScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PublishCommentScreen.java
@@ -97,7 +97,7 @@
     super.onInitUI();
     addStyleName(Gerrit.RESOURCES.css().publishCommentsScreen());
 
-    approvalButtons = new ArrayList<ValueRadioButton>();
+    approvalButtons = new ArrayList<>();
     descBlock = new ChangeDescriptionBlock(null);
     add(descBlock);
 
@@ -289,7 +289,7 @@
     if (nativeValues == null || nativeValues.length() == 0) {
       return;
     }
-    List<String> values = new ArrayList<String>(nativeValues.length());
+    List<String> values = new ArrayList<>(nativeValues.length());
     for (int i = 0; i < nativeValues.length(); i++) {
       values.add(nativeValues.get(i));
     }
@@ -350,7 +350,7 @@
     }
 
     draftsPanel.clear();
-    commentEditors = new ArrayList<CommentEditorPanel>();
+    commentEditors = new ArrayList<>();
 
     if (!drafts.isEmpty()) {
       draftsPanel.add(new SmallHeading(Util.C.headingPatchComments()));
@@ -468,8 +468,8 @@
   }
 
   private List<PatchLineComment> draftList() {
-    List<PatchLineComment> d = new ArrayList<PatchLineComment>();
-    List<String> paths = new ArrayList<String>(drafts.keySet());
+    List<PatchLineComment> d = new ArrayList<>();
+    List<String> paths = new ArrayList<>(drafts.keySet());
     Collections.sort(paths);
     for (String path : paths) {
       JsArray<CommentInfo> comments = drafts.get(path);
@@ -512,7 +512,7 @@
     SavedState(final PublishCommentScreen p) {
       patchSetId = p.patchSetId;
       message = p.message.getText();
-      approvals = new HashMap<String, String>();
+      approvals = new HashMap<>();
       for (final ValueRadioButton b : p.approvalButtons) {
         if (b.getValue()) {
           approvals.put(b.label.name(), b.value);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ReviewInput.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ReviewInput.java
index 0599a8b..812cadb 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ReviewInput.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ReviewInput.java
@@ -69,6 +69,14 @@
     }
   }-*/;
 
+  public final native void mergeLabels(ReviewInput o) /*-{
+    var l=o.labels;
+    if (l) {
+      for (var n in l)
+        this.labels[n]=l[n];
+    }
+  }-*/;
+
   protected ReviewInput() {
   }
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/ChunkManager.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/ChunkManager.java
index 36bd64f..dcea18c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/ChunkManager.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/ChunkManager.java
@@ -14,6 +14,8 @@
 
 package com.google.gerrit.client.diff;
 
+import static com.google.gerrit.client.diff.DisplaySide.A;
+import static com.google.gerrit.client.diff.DisplaySide.B;
 import static com.google.gerrit.client.diff.OverviewBar.MarkType.DELETE;
 import static com.google.gerrit.client.diff.OverviewBar.MarkType.EDIT;
 import static com.google.gerrit.client.diff.OverviewBar.MarkType.INSERT;
@@ -21,11 +23,14 @@
 import com.google.gerrit.client.diff.DiffInfo.Region;
 import com.google.gerrit.client.diff.DiffInfo.Span;
 import com.google.gerrit.client.rpc.Natives;
+import com.google.gwt.core.client.JavaScriptObject;
 import com.google.gwt.core.client.JsArray;
 import com.google.gwt.core.client.JsArrayString;
 import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NativeEvent;
 import com.google.gwt.dom.client.Style.Unit;
 import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.EventListener;
 
 import net.codemirror.lib.CodeMirror;
 import net.codemirror.lib.CodeMirror.LineClassWhere;
@@ -41,6 +46,34 @@
 
 /** Colors modified regions for {@link SideBySide2}. */
 class ChunkManager {
+  private static final JavaScriptObject focusA = initOnClick(A);
+  private static final JavaScriptObject focusB = initOnClick(B);
+  private static final native JavaScriptObject initOnClick(DisplaySide s) /*-{
+    return $entry(function(e){
+      @com.google.gerrit.client.diff.ChunkManager::focus(
+        Lcom/google/gwt/dom/client/NativeEvent;
+        Lcom/google/gerrit/client/diff/DisplaySide;)(e,s)
+    });
+  }-*/;
+
+  private static void focus(NativeEvent event, DisplaySide side) {
+    Element e = Element.as(event.getEventTarget());
+    for (e = DOM.getParent(e); e != null; e = DOM.getParent(e)) {
+      EventListener l = DOM.getEventListener(e);
+      if (l instanceof SideBySide2) {
+        ((SideBySide2) l).getCmFromSide(side).focus();
+        event.stopPropagation();
+      }
+    }
+  };
+
+  static void focusOnClick(Element e, DisplaySide side) {
+    onClick(e, side == A ? focusA : focusB);
+  }
+
+  private static final native void onClick(Element e, JavaScriptObject f)
+  /*-{ e.onclick = f }-*/;
+
   private final SideBySide2 host;
   private final CodeMirror cmA;
   private final CodeMirror cmB;
@@ -68,15 +101,7 @@
   }
 
   DiffChunkInfo getFirst() {
-    if (!chunks.isEmpty()) {
-      for (DiffChunkInfo d : chunks) {
-        if (d.getSide() == DisplaySide.B) {
-          return d;
-        }
-      }
-      return chunks.get(0);
-    }
-    return null;
+    return !chunks.isEmpty() ? chunks.get(0) : null;
   }
 
   void reset() {
@@ -228,6 +253,7 @@
       pad.setClassName(DiffTable.style.padding());
       pad.getStyle().setHeight(len, Unit.EM);
       pad.getStyle().setPaddingBottom(len, Unit.PX);
+      focusOnClick(pad, cm.side());
       padding.add(cm.addLineWidget(
         line == -1 ? 0 : line,
         pad,
@@ -263,7 +289,7 @@
 
         DiffChunkInfo lookUp = chunks.get(res);
         // If edit, skip the deletion chunk and set focus on the insertion one.
-        if (lookUp.isEdit() && lookUp.getSide() == DisplaySide.A) {
+        if (lookUp.isEdit() && lookUp.getSide() == A) {
           res = res + (dir == Direction.PREV ? -1 : 1);
           if (res < 0 || chunks.size() <= res) {
             return;
@@ -291,7 +317,7 @@
       public int compare(DiffChunkInfo a, DiffChunkInfo b) {
         if (a.getSide() == b.getSide()) {
           return a.getStart() - b.getStart();
-        } else if (a.getSide() == DisplaySide.A) {
+        } else if (a.getSide() == A) {
           int comp = mapper.lineOnOther(a.getSide(), a.getStart())
               .getLine() - b.getStart();
           return comp == 0 ? -1 : comp;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentBoxUi.css b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentBoxUi.css
index b95a86e..523cadc 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentBoxUi.css
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentBoxUi.css
@@ -73,7 +73,7 @@
 .message p,
 .message ul,
 .message blockquote {
-  -webkit-margin-before: 0;
+  -webkit-margin-before: 0.2em;
   -webkit-margin-after: 0.3em;
 }
 .commentBox button {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentGroup.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentGroup.java
index 9fc36b0..7bcf4da 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentGroup.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentGroup.java
@@ -61,6 +61,7 @@
 
     padding = DOM.createDiv();
     padding.setClassName(DiffTable.style.padding());
+    ChunkManager.focusOnClick(padding, cm.side());
     getElement().appendChild(padding);
   }
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.java
index 8a64e76..5765b22 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.java
@@ -18,7 +18,9 @@
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.core.client.JsArray;
+import com.google.gwt.core.client.JsArrayString;
 import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.Style.Unit;
 import com.google.gwt.resources.client.CssResource;
 import com.google.gwt.uibinder.client.UiBinder;
 import com.google.gwt.uibinder.client.UiField;
@@ -28,6 +30,8 @@
 import com.google.gwt.user.client.ui.UIObject;
 import com.google.gwt.user.client.ui.Widget;
 
+import net.codemirror.lib.CodeMirror;
+
 /**
  * A table with one row and two columns to hold the two CodeMirrors displaying
  * the files to be diffed.
@@ -47,6 +51,7 @@
     String rangeHighlight();
     String showTabs();
     String showLineNumbers();
+    String hideA();
     String columnMargin();
     String padding();
   }
@@ -57,6 +62,8 @@
   @UiField Element patchSetNavRow;
   @UiField Element patchSetNavCellA;
   @UiField Element patchSetNavCellB;
+  @UiField Element diffHeaderRow;
+  @UiField Element diffHeaderText;
   @UiField FlowPanel widgets;
   @UiField static DiffTableStyle style;
 
@@ -67,7 +74,9 @@
   PatchSetSelectBox2 patchSetSelectBoxB;
 
   private SideBySide2 parent;
+  private boolean header;
   private boolean headerVisible;
+  private boolean visibleA;
 
   DiffTable(SideBySide2 parent, PatchSet.Id base, PatchSet.Id revision,
       String path) {
@@ -80,6 +89,29 @@
     initWidget(uiBinder.createAndBindUi(this));
     this.parent = parent;
     this.headerVisible = true;
+    this.visibleA = true;
+  }
+
+  boolean isVisibleA() {
+    return visibleA;
+  }
+
+  void setVisibleA(boolean show) {
+    visibleA = show;
+    if (show) {
+      removeStyleName(style.hideA());
+    } else {
+      addStyleName(style.hideA());
+    }
+  }
+
+  Runnable toggleA() {
+    return new Runnable() {
+      @Override
+      public void run() {
+        setVisibleA(!isVisibleA());
+      }
+    };
   }
 
   boolean isHeaderVisible() {
@@ -89,6 +121,7 @@
   void setHeaderVisible(boolean show) {
     headerVisible = show;
     UIObject.setVisible(patchSetNavRow, show);
+    UIObject.setVisible(diffHeaderRow, show && header);
     if (show) {
       parent.header.removeStyleName(style.fullscreen());
     } else {
@@ -98,12 +131,49 @@
   }
 
   int getHeaderHeight() {
-    return patchSetSelectBoxA.getOffsetHeight();
+    int h = patchSetSelectBoxA.getOffsetHeight();
+    if (header) {
+      h += diffHeaderRow.getOffsetHeight();
+    }
+    return h;
   }
 
-  void setUpPatchSetNav(JsArray<RevisionInfo> list, DiffInfo info) {
+  void set(JsArray<RevisionInfo> list, DiffInfo info) {
     patchSetSelectBoxA.setUpPatchSetNav(list, info.meta_a());
     patchSetSelectBoxB.setUpPatchSetNav(list, info.meta_b());
+
+    JsArrayString hdr = info.diff_header();
+    if (hdr != null) {
+      StringBuilder b = new StringBuilder();
+      for (int i = 1; i < hdr.length(); i++) {
+        String s = hdr.get(i);
+        if (s.startsWith("diff --git ")
+            || s.startsWith("index ")
+            || s.startsWith("+++ ")
+            || s.startsWith("--- ")) {
+          continue;
+        }
+        b.append(s).append('\n');
+      }
+
+      String hdrTxt = b.toString().trim();
+      header = !hdrTxt.isEmpty();
+      diffHeaderText.setInnerText(hdrTxt);
+      UIObject.setVisible(diffHeaderRow, header);
+    } else {
+      header = false;
+      UIObject.setVisible(diffHeaderRow, false);
+    }
+  }
+
+  void refresh() {
+    overview.refresh();
+    if (header) {
+      CodeMirror cm = parent.getCmFromSide(DisplaySide.A);
+      diffHeaderText.getStyle().setMarginLeft(
+          cm.getGutterElement().getOffsetWidth(),
+          Unit.PX);
+    }
   }
 
   void add(Widget widget) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.ui.xml
index 09eacaa..436e72a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.ui.xml
@@ -52,6 +52,11 @@
       padding-bottom: 1px;
     }
 
+    .hideA .psNavA,
+    .hideA .a {
+      display: none;
+    }
+
     .table {
       width: 100%;
       table-layout: fixed;
@@ -152,11 +157,17 @@
       z-index: 2;
       cursor: text;
     }
+    .diff_header {
+      margin: 0 0 3px 0;
+      font-size: 12px;
+      font-weight: bold;
+      color: #5252ad;
+    }
   </ui:style>
   <g:HTMLPanel styleName='{style.difftable}'>
     <table class='{style.table}'>
       <tr ui:field='patchSetNavRow' class='{style.patchSetNav}'>
-        <td ui:field='patchSetNavCellA'>
+        <td ui:field='patchSetNavCellA' class='{style.psNavA}'>
           <d:PatchSetSelectBox2 ui:field='patchSetSelectBoxA' />
         </td>
         <td ui:field='patchSetNavCellB'>
@@ -164,6 +175,12 @@
         </td>
         <td class='{style.overview}' />
       </tr>
+      <tr ui:field='diffHeaderRow' class='{style.patchSetNav}'>
+        <td colspan='2'><pre
+            ui:field='diffHeaderText'
+            class='{style.diff_header}' /></td>
+        <td class='{style.overview}' />
+      </tr>
       <tr>
         <td ui:field='cmA' class='{style.a}' />
         <td ui:field='cmB' class='{style.b}' />
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/EditIterator.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/EditIterator.java
index 246c101..4c8d80e 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/EditIterator.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/EditIterator.java
@@ -22,8 +22,8 @@
 class EditIterator {
   private final JsArrayString lines;
   private final int startLine;
-  private int currLineIndex;
-  private int currLineOffset;
+  private int line;
+  private int pos;
 
   EditIterator(JsArrayString lineArray, int start) {
     lines = lineArray;
@@ -31,27 +31,44 @@
   }
 
   LineCharacter advance(int numOfChar) {
-    while (currLineIndex < lines.length()) {
-      int lengthWithNewline =
-          lines.get(currLineIndex).length() - currLineOffset + 1;
-      if (numOfChar < lengthWithNewline) {
+    numOfChar = adjustForNegativeDelta(numOfChar);
+
+    while (line < lines.length()) {
+      int len = lines.get(line).length() - pos + 1; // + 1 for LF
+      if (numOfChar < len) {
         LineCharacter at = LineCharacter.create(
-            startLine + currLineIndex,
-            numOfChar + currLineOffset);
-        currLineOffset += numOfChar;
+            startLine + line,
+            numOfChar + pos);
+        pos += numOfChar;
         return at;
       }
-      numOfChar -= lengthWithNewline;
-      advanceLine();
+
+      numOfChar -= len;
+      line++;
+      pos = 0;
+
       if (numOfChar == 0) {
-        return LineCharacter.create(startLine + currLineIndex, 0);
+        return LineCharacter.create(startLine + line, 0);
       }
     }
-    throw new IllegalStateException("EditIterator index out of bound");
+
+    throw new IllegalStateException("EditIterator index out of bounds");
   }
 
-  private void advanceLine() {
-    currLineIndex++;
-    currLineOffset = 0;
+  private int adjustForNegativeDelta(int n) {
+    while (n < 0) {
+      if (-n <= pos) {
+        pos += n;
+        return 0;
+      }
+
+      n += pos;
+      line--;
+      if (line < 0) {
+        throw new IllegalStateException("EditIterator index out of bounds");
+      }
+      pos = lines.get(line).length() + 1;
+    }
+    return n;
   }
-}
\ No newline at end of file
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.java
index ed7c3b6..050e27a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.java
@@ -32,6 +32,8 @@
 import com.google.gerrit.reviewdb.client.AccountDiffPreference.Theme;
 import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
 import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.core.client.Scheduler.RepeatingCommand;
 import com.google.gwt.event.dom.client.ChangeEvent;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.KeyDownEvent;
@@ -52,6 +54,12 @@
 import com.google.gwt.user.client.ui.PopupPanel;
 import com.google.gwt.user.client.ui.ToggleButton;
 
+import net.codemirror.lib.ModeInjector;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
 /** Displays current diff preferences. */
 class PreferencesBox extends Composite {
   interface Binder extends UiBinder<HTMLPanel, PreferencesBox> {}
@@ -78,11 +86,13 @@
   @UiField ToggleButton whitespaceErrors;
   @UiField ToggleButton showTabs;
   @UiField ToggleButton lineNumbers;
+  @UiField ToggleButton leftSide;
   @UiField ToggleButton topMenu;
   @UiField ToggleButton manualReview;
   @UiField ToggleButton expandAllComments;
   @UiField ToggleButton renderEntireFile;
   @UiField ListBox theme;
+  @UiField ListBox mode;
   @UiField Button apply;
   @UiField Button save;
 
@@ -92,6 +102,7 @@
     initWidget(uiBinder.createAndBindUi(this));
     initIgnoreWhitespace();
     initTheme();
+    initMode();
   }
 
   @Override
@@ -114,6 +125,16 @@
         if (prefs.context() == WHOLE_FILE_CONTEXT) {
           contextEntireFile.setValue(true);
         }
+        if (view.canEnableRenderEntireFile(prefs)) {
+          renderEntireFile.setEnabled(true);
+        } else {
+          if (prefs.renderEntireFile()) {
+            prefs.renderEntireFile(false);
+            renderEntireFile.setValue(false);
+            view.updateRenderEntireFile();
+          }
+          renderEntireFile.setEnabled(false);
+        }
         view.setContext(prefs.context());
       }
     };
@@ -129,12 +150,19 @@
     whitespaceErrors.setValue(prefs.showWhitespaceErrors());
     showTabs.setValue(prefs.showTabs());
     lineNumbers.setValue(prefs.showLineNumbers());
+    leftSide.setValue(view.diffTable.isVisibleA());
     topMenu.setValue(!prefs.hideTopMenu());
     manualReview.setValue(prefs.manualReview());
     expandAllComments.setValue(prefs.expandAllComments());
     renderEntireFile.setValue(prefs.renderEntireFile());
+    renderEntireFile.setEnabled(view.canEnableRenderEntireFile(prefs));
     setTheme(prefs.theme());
 
+    mode.setEnabled(prefs.syntaxHighlighting());
+    if (prefs.syntaxHighlighting()) {
+      setMode(view.getContentType());
+    }
+
     switch (view.getIntraLineStatus()) {
       case OFF:
       case OK:
@@ -262,6 +290,11 @@
     view.setShowLineNumbers(prefs.showLineNumbers());
   }
 
+  @UiHandler("leftSide")
+  void onLeftSide(ValueChangeEvent<Boolean> e) {
+    view.diffTable.setVisibleA(e.getValue());
+  }
+
   @UiHandler("topMenu")
   void onTopMenu(ValueChangeEvent<Boolean> e) {
     prefs.hideTopMenu(!e.getValue());
@@ -277,9 +310,35 @@
   @UiHandler("syntaxHighlighting")
   void onSyntaxHighlighting(ValueChangeEvent<Boolean> e) {
     prefs.syntaxHighlighting(e.getValue());
+    mode.setEnabled(prefs.syntaxHighlighting());
+    if (prefs.syntaxHighlighting()) {
+      setMode(view.getContentType());
+    }
     view.setSyntaxHighlighting(prefs.syntaxHighlighting());
   }
 
+  @UiHandler("mode")
+  void onMode(ChangeEvent e) {
+    final String m = mode.getValue(mode.getSelectedIndex());
+    prefs.syntaxHighlighting(true);
+    syntaxHighlighting.setValue(true, false);
+    Scheduler.get().scheduleFixedDelay(new RepeatingCommand() {
+      @Override
+      public boolean execute() {
+        if (prefs.syntaxHighlighting() && view.isAttached()) {
+          view.operation(new Runnable() {
+            @Override
+            public void run() {
+              view.getCmFromSide(DisplaySide.A).setOption("mode", m);
+              view.getCmFromSide(DisplaySide.B).setOption("mode", m);
+            }
+          });
+        }
+        return false;
+      }
+    }, 50);
+  }
+
   @UiHandler("whitespaceErrors")
   void onWhitespaceErrors(ValueChangeEvent<Boolean> e) {
     prefs.showWhitespaceErrors(e.getValue());
@@ -374,6 +433,51 @@
         IGNORE_ALL_SPACE.name());
   }
 
+  private static final Map<String, String> NAME_TO_MODE;
+  private static final Map<String, String> NORMALIZED_MODES;
+  static {
+    NAME_TO_MODE = new TreeMap<>();
+    NORMALIZED_MODES = new HashMap<>();
+    for (String type : ModeInjector.getKnownMimeTypes()) {
+      String name = type;
+      if (name.startsWith("text/x-")) {
+        name = name.substring("text/x-".length());
+      } else if (name.startsWith("text/")) {
+        name = name.substring("text/".length());
+      } else if (name.startsWith("application/")) {
+        name = name.substring("application/".length());
+      }
+
+      String normalized = NAME_TO_MODE.get(name);
+      if (normalized == null) {
+        normalized = type;
+        NAME_TO_MODE.put(name, normalized);
+      }
+      NORMALIZED_MODES.put(type, normalized);
+    }
+  }
+
+  private void initMode() {
+    for (Map.Entry<String, String> e : NAME_TO_MODE.entrySet()) {
+      mode.addItem(e.getKey(), e.getValue());
+    }
+  }
+
+  private void setMode(String modeType) {
+    if (modeType != null && !modeType.isEmpty()) {
+      if (NORMALIZED_MODES.containsKey(modeType)) {
+        modeType = NORMALIZED_MODES.get(modeType);
+      }
+      for (int i = 0; i < mode.getItemCount(); i++) {
+        if (mode.getValue(i).equals(modeType)) {
+          mode.setSelectedIndex(i);
+          return;
+        }
+      }
+    }
+    mode.setSelectedIndex(0);
+  }
+
   private void setTheme(Theme v) {
     String name = v != null ? v.name() : Theme.DEFAULT.name();
     for (int i = 0; i < theme.getItemCount(); i++) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.ui.xml
index d940590..670c3e3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PreferencesBox.ui.xml
@@ -204,6 +204,10 @@
         </g:ToggleButton></td>
       </tr>
       <tr>
+        <th><ui:msg>Language</ui:msg></th>
+        <td><g:ListBox ui:field='mode'/></td>
+      </tr>
+      <tr>
         <th><ui:msg>Whitespace Errors</ui:msg></th>
         <td><g:ToggleButton ui:field='whitespaceErrors'>
           <g:upFace><ui:msg>Hide</ui:msg></g:upFace>
@@ -225,6 +229,13 @@
         </g:ToggleButton></td>
       </tr>
       <tr>
+        <th><ui:msg>Left Side</ui:msg></th>
+        <td><g:ToggleButton ui:field='leftSide'>
+          <g:upFace><ui:msg>Hide</ui:msg></g:upFace>
+          <g:downFace><ui:msg>Show</ui:msg></g:downFace>
+        </g:ToggleButton></td>
+      </tr>
+      <tr>
         <th><ui:msg>Top Menu</ui:msg></th>
         <td><g:ToggleButton ui:field='topMenu'>
           <g:upFace><ui:msg>Hide</ui:msg></g:upFace>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide2.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide2.java
index 3943b69..fce95ad 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide2.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide2.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.client.diff;
 
+import static com.google.gerrit.reviewdb.client.AccountDiffPreference.WHOLE_FILE_CONTEXT;
 import static java.lang.Double.POSITIVE_INFINITY;
 
 import com.google.gerrit.client.Gerrit;
@@ -24,6 +25,7 @@
 import com.google.gerrit.client.changes.ChangeInfo;
 import com.google.gerrit.client.changes.ChangeInfo.RevisionInfo;
 import com.google.gerrit.client.changes.ChangeList;
+import com.google.gerrit.client.diff.DiffInfo.FileMeta;
 import com.google.gerrit.client.diff.LineMapper.LineOnOtherInfo;
 import com.google.gerrit.client.patches.PatchUtil;
 import com.google.gerrit.client.projects.ConfigInfoCache;
@@ -83,6 +85,18 @@
   interface Binder extends UiBinder<FlowPanel, SideBySide2> {}
   private static final Binder uiBinder = GWT.create(Binder.class);
 
+  enum FileSize {
+    SMALL(0),
+    LARGE(500),
+    HUGE(4000);
+
+    final int lines;
+
+    FileSize(int n) {
+      this.lines = n;
+    }
+  }
+
   @UiField(provided = true)
   Header header;
 
@@ -103,7 +117,7 @@
   private Element columnMarginB;
   private HandlerRegistration resizeHandler;
   private DiffInfo diff;
-  private boolean largeFile;
+  private FileSize fileSize;
   private ChunkManager chunkManager;
   private CommentManager commentManager;
   private SkipManager skipManager;
@@ -163,8 +177,8 @@
         public void onSuccess(DiffInfo diffInfo) {
           diff = diffInfo;
           if (prefs.syntaxHighlighting()) {
-            largeFile = isLargeFile(diffInfo);
-            if (largeFile) {
+            fileSize = bucketFileSize(diffInfo);
+            if (fileSize.compareTo(FileSize.SMALL) > 0) {
               modeInjectorCb.onSuccess(null);
             } else {
               injectMode(diffInfo, modeInjectorCb);
@@ -187,7 +201,7 @@
         info.revisions().copyKeysIntoChildren("name");
         JsArray<RevisionInfo> list = info.revisions().values();
         RevisionInfo.sortRevisionInfoByNumber(list);
-        diffTable.setUpPatchSetNav(list, diff);
+        diffTable.set(list, diff);
         header.setChangeInfo(info);
       }}));
 
@@ -231,13 +245,18 @@
       }
     });
     setLineLength(prefs.lineLength());
-    diffTable.overview.refresh();
+    diffTable.refresh();
 
-    if (startLine == 0 && diff.meta_b() != null) {
+    if (startLine == 0) {
       DiffChunkInfo d = chunkManager.getFirst();
       if (d != null) {
-        startSide = d.getSide();
-        startLine = d.getStart() + 1;
+        if (d.isEdit() && d.getSide() == DisplaySide.A) {
+          startSide = DisplaySide.B;
+          startLine = lineOnOther(d.getSide(), d.getStart()).getLine() + 1;
+        } else {
+          startSide = d.getSide();
+          startLine = d.getStart() + 1;
+        }
       }
     }
     if (startSide != null && startLine > 0) {
@@ -310,6 +329,7 @@
         .on("C", commentManager.insertNewDraft(cm))
         .on("N", maybeNextVimSearch(cm))
         .on("P", chunkManager.diffChunkNav(cm, Direction.PREV))
+        .on("Shift-A", diffTable.toggleA())
         .on("Shift-M", header.reviewedAndNext())
         .on("Shift-N", maybePrevVimSearch(cm))
         .on("Shift-P", commentManager.commentNav(cm, Direction.PREV))
@@ -404,6 +424,9 @@
 
     keysNavigation.add(new UpToChangeCommand2(revision, 0, 'u'));
     keysNavigation.add(
+        new NoOpKeyCommand(KeyCommand.M_SHIFT, KeyCodes.KEY_LEFT, PatchUtil.C.focusSideA()),
+        new NoOpKeyCommand(KeyCommand.M_SHIFT, KeyCodes.KEY_RIGHT, PatchUtil.C.focusSideB()));
+    keysNavigation.add(
         new NoOpKeyCommand(0, 'j', PatchUtil.C.lineNext()),
         new NoOpKeyCommand(0, 'k', PatchUtil.C.linePrev()));
     keysNavigation.add(
@@ -440,6 +463,13 @@
         upToChange(true).run();
       }
     });
+    keysAction.add(new KeyCommand(
+        KeyCommand.M_SHIFT, 'a', PatchUtil.C.toggleSideA()) {
+      @Override
+      public void onKeyPress(KeyPressEvent event) {
+        diffTable.toggleA().run();
+      }
+    });
     keysAction.add(new KeyCommand(0, ',', PatchUtil.C.showPreferences()) {
       @Override
       public void onKeyPress(KeyPressEvent event) {
@@ -468,11 +498,11 @@
     }
 
     removeKeyHandlerRegistrations();
+    handlers.add(GlobalKey.add(this, keysAction));
     handlers.add(GlobalKey.add(this, keysNavigation));
     if (keysComment != null) {
       handlers.add(GlobalKey.add(this, keysComment));
     }
-    handlers.add(GlobalKey.add(this, keysAction));
     handlers.add(ShowHelpCommand.addFocusHandler(new FocusHandler() {
       @Override
       public void onFocus(FocusEvent event) {
@@ -502,6 +532,11 @@
     cmA.getMoverElement().appendChild(columnMarginA);
     cmB.getMoverElement().appendChild(columnMarginB);
 
+    if (prefs.renderEntireFile() && !canEnableRenderEntireFile(prefs)) {
+      // CodeMirror is too slow to layout an entire huge file.
+      prefs.renderEntireFile(false);
+    }
+
     operation(new Runnable() {
       public void run() {
         // Estimate initial CM3 height, fixed up in onShowView.
@@ -523,7 +558,7 @@
     prefsAction = new PreferencesAction(this, prefs);
     header.init(prefsAction);
 
-    if (largeFile && prefs.syntaxHighlighting()) {
+    if (prefs.syntaxHighlighting() && fileSize.compareTo(FileSize.SMALL) > 0) {
       Scheduler.get().scheduleFixedDelay(new RepeatingCommand() {
         @Override
         public boolean execute() {
@@ -541,13 +576,16 @@
       String contents,
       DisplaySide side,
       Element parent) {
+    String mode = fileSize == FileSize.SMALL
+        ? getContentType(meta)
+        : null;
     return CodeMirror.create(side, parent, Configuration.create()
       .set("readOnly", true)
       .set("cursorBlinkRate", 0)
       .set("cursorHeight", 0.85)
       .set("lineNumbers", prefs.showLineNumbers())
       .set("tabSize", prefs.tabSize())
-      .set("mode", largeFile ? null : getContentType(meta))
+      .set("mode", mode)
       .set("lineWrapping", false)
       .set("styleSelectedText", true)
       .set("showTrailingSpace", prefs.showWhitespaceErrors())
@@ -561,6 +599,15 @@
     return diff.intraline_status();
   }
 
+  boolean canEnableRenderEntireFile(DiffPreferences prefs) {
+    return fileSize.compareTo(FileSize.HUGE) < 0
+        || (prefs.context() != WHOLE_FILE_CONTEXT && prefs.context() < 100);
+  }
+
+  String getContentType() {
+    return getContentType(diff.meta_b());
+  }
+
   void setThemeStyles(boolean d) {
     if (d) {
       diffTable.addStyleName(DiffTable.style.dark());
@@ -931,8 +978,17 @@
       });
   }
 
-  private static boolean isLargeFile(DiffInfo diffInfo) {
-    return (diffInfo.meta_a() != null && diffInfo.meta_a().lines() > 500)
-        || (diffInfo.meta_b() != null && diffInfo.meta_b().lines() > 500);
+  private static FileSize bucketFileSize(DiffInfo diff) {
+    FileMeta a = diff.meta_a();
+    FileMeta b = diff.meta_b();
+    FileSize[] sizes = FileSize.values();
+    for (int i = sizes.length - 1; 0 <= i; i--) {
+      FileSize s = sizes[i];
+      if ((a != null && s.lines <= a.lines())
+          || (b != null && s.lines <= b.lines())) {
+        return s;
+      }
+    }
+    return FileSize.SMALL;
   }
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupMap.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupMap.java
index 6ba00ae..f28fb86 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupMap.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupMap.java
@@ -24,12 +24,18 @@
     groups().get(NativeMap.copyKeysIntoChildren(callback));
   }
 
-  public static void match(String match, AsyncCallback<GroupMap> cb) {
-    if (match == null || "".equals(match)) {
-      all(cb);
-    } else {
-      groups().addParameter("m", match).get(NativeMap.copyKeysIntoChildren(cb));
+  public static void match(String match, int limit, int start, AsyncCallback<GroupMap> cb) {
+    RestApi call = groups();
+    if (match != null) {
+      call.addParameter("m", match);
     }
+    if (limit > 0) {
+      call.addParameter("n", limit);
+    }
+    if (start > 0) {
+      call.addParameter("S", start);
+    }
+    call.get(NativeMap.copyKeysIntoChildren(cb));
   }
 
   public static void myOwned(AsyncCallback<GroupMap> cb) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java
index ae0b786..9ff9893 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java
@@ -49,9 +49,12 @@
   String chunkNext2();
   String commentPrev();
   String commentNext();
+  String focusSideA();
+  String focusSideB();
   String fileList();
   String expandComment();
   String expandAllCommentsOnCurrentLine();
+  String toggleSideA();
   String toggleIntraline();
   String showPreferences();
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties
index 3e021c7..0a47613 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties
@@ -31,9 +31,12 @@
 chunkNext2 = Next diff chunk or search result
 commentPrev = Previous comment
 commentNext = Next comment
+focusSideA = Focus left side
+focusSideB = Focus right side
 fileList = Browse files in patch set
 expandComment = Expand or collapse comment
 expandAllCommentsOnCurrentLine = Expand or collapse all comments on current line
+toggleSideA = Toggle left side
 toggleIntraline = Toggle intraline difference
 showPreferences = Show diff preferences
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.java
index e45ee1f..083820b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.java
@@ -90,7 +90,7 @@
     this.idSideA = idSideA;
     this.idSideB = idSideB;
     this.idActive = (side == Side.A) ? idSideA : idSideB;
-    this.links = new HashMap<Integer, Anchor>();
+    this.links = new HashMap<>();
 
     linkPanel.clear();
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/RestApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/RestApi.java
index da620d8..2bc4ac1 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/RestApi.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/RestApi.java
@@ -327,7 +327,7 @@
 
   private <T extends JavaScriptObject> void send(
       Method method, AsyncCallback<T> cb) {
-    HttpCallback<T> httpCallback = new HttpCallback<T>(background, cb);
+    HttpCallback<T> httpCallback = new HttpCallback<>(background, cb);
     try {
       if (!background) {
         RpcStatus.INSTANCE.onRpcStart();
@@ -367,7 +367,7 @@
   private <T extends JavaScriptObject> void sendJSON(
       Method method, JavaScriptObject content,
       AsyncCallback<T> cb) {
-    HttpCallback<T> httpCallback = new HttpCallback<T>(background, cb);
+    HttpCallback<T> httpCallback = new HttpCallback<>(background, cb);
     try {
       if (!background) {
         RpcStatus.INSTANCE.onRpcStart();
@@ -384,7 +384,7 @@
 
   private <T extends JavaScriptObject> void sendRaw(Method method, String body,
       AsyncCallback<T> cb) {
-    HttpCallback<T> httpCallback = new HttpCallback<T>(background, cb);
+    HttpCallback<T> httpCallback = new HttpCallback<>(background, cb);
     try {
       if (!background) {
         RpcStatus.INSTANCE.onRpcStart();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CherryPickDialog.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CherryPickDialog.java
index 1d5a74f..54c4c53 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CherryPickDialog.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CherryPickDialog.java
@@ -50,8 +50,7 @@
     newBranch = new SuggestBox(new HighlightSuggestOracle() {
       @Override
       protected void onRequestSuggestions(Request request, Callback done) {
-        LinkedList<BranchSuggestion> suggestions =
-            new LinkedList<BranchSuggestion>();
+        LinkedList<BranchSuggestion> suggestions = new LinkedList<>();
         for (final BranchInfo b : branches) {
           if (b.ref().contains(request.getQuery())) {
             suggestions.add(new BranchSuggestion(b));
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Hyperlink.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Hyperlink.java
index 99766c4..2108ad4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Hyperlink.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Hyperlink.java
@@ -23,7 +23,7 @@
 
 /** Standard GWT hyperlink with late updating of the token. */
 public class Hyperlink extends com.google.gwt.user.client.ui.Hyperlink {
-  static final HyperlinkImpl impl = GWT.create(HyperlinkImpl.class);
+  public static final HyperlinkImpl impl = GWT.create(HyperlinkImpl.class);
 
   /** Initialize a default hyperlink with no target and no text. */
   public Hyperlink() {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ScreenLoadEvent.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ScreenLoadEvent.java
index 562e53a..45ba808 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ScreenLoadEvent.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ScreenLoadEvent.java
@@ -24,7 +24,7 @@
     this.screen = screen;
   }
 
-  public static final Type<ScreenLoadHandler> TYPE = new Type<ScreenLoadHandler>();
+  public static final Type<ScreenLoadHandler> TYPE = new Type<>();
 
   @Override
   protected void dispatch(ScreenLoadHandler handler) {
diff --git a/gerrit-gwtui/src/main/java/net/codemirror/lib/ModeInjector.java b/gerrit-gwtui/src/main/java/net/codemirror/lib/ModeInjector.java
index 02faccb..3d77d09 100644
--- a/gerrit-gwtui/src/main/java/net/codemirror/lib/ModeInjector.java
+++ b/gerrit-gwtui/src/main/java/net/codemirror/lib/ModeInjector.java
@@ -21,6 +21,7 @@
 
 import net.codemirror.mode.Modes;
 
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -94,6 +95,10 @@
     return real != null ? real : mode;
   }
 
+  public static Collection<String> getKnownMimeTypes() {
+    return mimeModes.keySet();
+  }
+
   private static native boolean isModeLoaded(String n)
   /*-{ return $wnd.CodeMirror.modes.hasOwnProperty(n); }-*/;
 
diff --git a/gerrit-gwtui/src/test/java/com/google/gerrit/client/diff/EditIteratorTest.java b/gerrit-gwtui/src/test/java/com/google/gerrit/client/diff/EditIteratorTest.java
index 12a616a..1ebf6bb 100644
--- a/gerrit-gwtui/src/test/java/com/google/gerrit/client/diff/EditIteratorTest.java
+++ b/gerrit-gwtui/src/test/java/com/google/gerrit/client/diff/EditIteratorTest.java
@@ -45,6 +45,13 @@
   }
 
   @Test
+  public void testNegativeAdvance() {
+    EditIterator i = new EditIterator(lines, 0);
+    assertLineChsEqual(LineCharacter.create(1, 1), i.advance(5));
+    assertLineChsEqual(LineCharacter.create(0, 3), i.advance(-2));
+  }
+
+  @Test
   public void testNoAdvance() {
     EditIterator iter = new EditIterator(lines, 0);
     assertLineChsEqual(LineCharacter.create(0), iter.advance(0));
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/DirectChangeByCommit.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/DirectChangeByCommit.java
index 402ea1b..11383ca 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/DirectChangeByCommit.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/DirectChangeByCommit.java
@@ -50,7 +50,7 @@
   protected void doGet(final HttpServletRequest req,
       final HttpServletResponse rsp) throws IOException {
     String query = CharMatcher.is('/').trimTrailingFrom(req.getPathInfo());
-    HashSet<Change.Id> ids = new HashSet<Change.Id>();
+    HashSet<Change.Id> ids = new HashSet<>();
     try {
       ChangeQueryBuilder builder = queryBuilder.create(currentUser.get());
       Predicate<ChangeData> visibleToMe = builder.is_visible();
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GerritConfigProvider.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GerritConfigProvider.java
index 28a9190..bbe6972 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GerritConfigProvider.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GerritConfigProvider.java
@@ -152,7 +152,7 @@
         reportBugUrl : "http://code.google.com/p/gerrit/issues/list");
     config.setReportBugText(cfg.getString("gerrit", null, "reportBugText"));
 
-    final Set<Account.FieldName> fields = new HashSet<Account.FieldName>();
+    final Set<Account.FieldName> fields = new HashSet<>();
     for (final Account.FieldName n : Account.FieldName.values()) {
       if (realm.allowsEdit(n)) {
         fields.add(n);
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java
index 03d54e4..24c2afa 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java
@@ -356,7 +356,7 @@
 
       if (isGet) {
         cache.put(cacheKey, Collections.unmodifiableSet(
-            new HashSet<ObjectId>(rp.getAdvertisedObjects())));
+            new HashSet<>(rp.getAdvertisedObjects())));
       }
     }
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java
index d299f54..3a45089 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java
@@ -25,6 +25,7 @@
 import com.google.gerrit.server.account.AccountState;
 import com.google.gerrit.server.account.AuthRequest;
 import com.google.gerrit.server.account.AuthResult;
+import com.google.gerrit.server.auth.NoSuchUserException;
 import com.google.gerrit.server.config.AuthConfig;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -155,6 +156,18 @@
       ws.setAccessPathOk(AccessPath.GIT, true);
       ws.setAccessPathOk(AccessPath.REST_API, true);
       return true;
+    } catch (NoSuchUserException e) {
+      if (password.equals(who.getPassword(who.getUserName()))) {
+        WebSession ws = session.get();
+        ws.setUserAccountId(who.getAccount().getId());
+        ws.setAccessPathOk(AccessPath.GIT, true);
+        ws.setAccessPathOk(AccessPath.REST_API, true);
+        return true;
+      } else {
+        log.warn("Authentication failed for " + username, e);
+        rsp.sendError(SC_UNAUTHORIZED);
+        return false;
+      }
     } catch (AccountException e) {
       log.warn("Authentication failed for " + username, e);
       rsp.sendError(SC_UNAUTHORIZED);
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectDigestFilter.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectDigestFilter.java
index 45e4504..be22256 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectDigestFilter.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectDigestFilter.java
@@ -231,7 +231,7 @@
   }
 
   private Map<String, String> parseAuthorization(String auth) {
-    Map<String, String> p = new HashMap<String, String>();
+    Map<String, String> p = new HashMap<>();
     int next = "Digest ".length();
     while (next < auth.length()) {
       if (next < auth.length() && auth.charAt(next) == ',') {
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebServlet.java
index c2b0cc8..f831ab5 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebServlet.java
@@ -98,7 +98,7 @@
     this.projectControl = projectControl;
     this.anonymousUserProvider = anonymousUserProvider;
     this.gitwebCgi = gitWebConfig.getGitwebCGI();
-    this.deniedActions = new HashSet<String>();
+    this.deniedActions = new HashSet<>();
 
     final String url = gitWebConfig.getUrl();
     if ((url != null) && (!url.equals("gitweb"))) {
@@ -398,7 +398,7 @@
   }
 
   private static Map<String, String> getParameters(HttpServletRequest req) {
-    final Map<String, String> params = new HashMap<String, String>();
+    final Map<String, String> params = new HashMap<>();
     for (final String pair : req.getQueryString().split("[&;]")) {
       final int eq = pair.indexOf('=');
       if (0 < eq) {
@@ -669,11 +669,11 @@
     private Map<String, String> envMap;
 
     EnvList() {
-      envMap = new HashMap<String, String>();
+      envMap = new HashMap<>();
     }
 
     EnvList(final EnvList l) {
-      envMap = new HashMap<String, String>(l.envMap);
+      envMap = new HashMap<>(l.envMap);
     }
 
     /** Set a name/value pair, null values will be treated as an empty String */
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/HostPageServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/HostPageServlet.java
index fda2c0d..608aad6 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/HostPageServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/HostPageServlet.java
@@ -330,7 +330,7 @@
       nocache.setAttribute("src", noCacheName);
       opt = new Content(hostDoc);
 
-      nocache.setAttribute("src", "gerrit_ui/gerrit_dbg.nocache.js");
+      nocache.setAttribute("src", "gerrit_ui/dbg_gerrit_ui.nocache.js");
       debug = new Content(hostDoc);
     }
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/RestApiServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
index ce450dc..2f41c94 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
@@ -206,7 +206,7 @@
       RestResource rsrc = TopLevelResource.INSTANCE;
       ViewData viewData = new ViewData(null, null);
       if (path.isEmpty()) {
-        if ("GET".equals(req.getMethod())) {
+        if (isGetOrHead(req)) {
           viewData = new ViewData(null, rc.list());
         } else if (rc instanceof AcceptsPost && "POST".equals(req.getMethod())) {
           @SuppressWarnings("unchecked")
@@ -247,7 +247,7 @@
             (RestCollection<RestResource, RestResource>) viewData.view;
 
         if (path.isEmpty()) {
-          if ("GET".equals(req.getMethod())) {
+          if (isGetOrHead(req)) {
             viewData = new ViewData(null, c.list());
           } else if (c instanceof AcceptsPost && "POST".equals(req.getMethod())) {
             @SuppressWarnings("unchecked")
@@ -363,7 +363,7 @@
   }
 
   private static boolean notModified(HttpServletRequest req, RestResource rsrc) {
-    if (!"GET".equals(req.getMethod())) {
+    if (!isGetOrHead(req)) {
       return false;
     }
 
@@ -386,7 +386,7 @@
 
   private static <T> void configureCaching(HttpServletRequest req,
       HttpServletResponse res, RestResource rsrc, CacheControl c) {
-    if ("GET".equals(req.getMethod())) {
+    if (isGetOrHead(req)) {
       switch (c.getType()) {
         case NONE:
         default:
@@ -716,11 +716,13 @@
         res.setHeader("Content-Length", Long.toString(len));
       }
 
-      OutputStream dst = res.getOutputStream();
-      try {
-        bin.writeTo(dst);
-      } finally {
-        dst.close();
+      if (req == null || !"HEAD".equals(req.getMethod())) {
+        OutputStream dst = res.getOutputStream();
+        try {
+          bin.writeTo(dst);
+        } finally {
+          dst.close();
+        }
       }
     } finally {
       appResult.close();
@@ -787,6 +789,8 @@
       // is chosen, look for the projection based upon GET as the method as
       // the client thinks it is a nested collection.
       method = "GET";
+    } else if ("HEAD".equals(method)) {
+      method = "GET";
     }
 
     List<String> p = splitProjection(projection);
@@ -879,9 +883,12 @@
     user.setAccessPath(AccessPath.REST_API);
   }
 
+  private static boolean isGetOrHead(HttpServletRequest req) {
+    return "GET".equals(req.getMethod()) || "HEAD".equals(req.getMethod());
+  }
+
   private static boolean isStateChange(HttpServletRequest req) {
-    String method = req.getMethod();
-    return !("GET".equals(method) || "HEAD".equals(method));
+    return !isGetOrHead(req);
   }
 
   private void checkRequiresCapability(ViewData viewData) throws AuthException {
@@ -913,12 +920,12 @@
       CacheControl c) throws IOException {
     res.setStatus(statusCode);
     configureCaching(req, res, null, c);
-    replyText(null, res, msg);
+    replyText(req, res, msg);
   }
 
   static void replyText(@Nullable HttpServletRequest req,
       HttpServletResponse res, String text) throws IOException {
-    if ((req == null || "GET".equals(req.getMethod())) && isMaybeHTML(text)) {
+    if ((req == null || isGetOrHead(req)) && isMaybeHTML(text)) {
       replyJson(req, res, ImmutableMultimap.of("pp", "0"), new JsonPrimitive(text));
     } else {
       if (!text.endsWith("\n")) {
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/GerritJsonServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/GerritJsonServlet.java
index ec96f0b..0b453a0 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/GerritJsonServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/GerritJsonServlet.java
@@ -51,9 +51,9 @@
 final class GerritJsonServlet extends JsonServlet<GerritJsonServlet.GerritCall> {
   private static final Logger log = LoggerFactory.getLogger(GerritJsonServlet.class);
   private static final ThreadLocal<GerritCall> currentCall =
-      new ThreadLocal<GerritCall>();
+      new ThreadLocal<>();
   private static final ThreadLocal<MethodHandle> currentMethod =
-      new ThreadLocal<MethodHandle>();
+      new ThreadLocal<>();
   private final Provider<WebSession> session;
   private final RemoteJsonService service;
   private final AuditService audit;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SuggestServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SuggestServiceImpl.java
index f8d43a8..dcd181c 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SuggestServiceImpl.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SuggestServiceImpl.java
@@ -137,8 +137,7 @@
     final int max = 10;
     final int n = limit <= 0 ? max : Math.min(limit, max);
 
-    final LinkedHashMap<Account.Id, AccountInfo> r =
-        new LinkedHashMap<Account.Id, AccountInfo>();
+    LinkedHashMap<Account.Id, AccountInfo> r = new LinkedHashMap<>();
     for (final Account p : db.accounts().suggestByFullName(a, b, n)) {
       addSuggestion(r, p, new AccountInfo(p), active, visibilityControl);
     }
@@ -159,7 +158,7 @@
         }
       }
     }
-    return new ArrayList<AccountInfo>(r.values());
+    return new ArrayList<>(r.values());
   }
 
   private void addSuggestion(Map<Account.Id, AccountInfo> map, Account account,
@@ -251,7 +250,7 @@
         final List<AccountInfo> suggestedAccounts =
             suggestAccount(db, query, Boolean.TRUE, limit, visibilityControl);
         final List<ReviewerInfo> reviewer =
-            new ArrayList<ReviewerInfo>(suggestedAccounts.size());
+            new ArrayList<>(suggestedAccounts.size());
         for (final AccountInfo a : suggestedAccounts) {
           reviewer.add(new ReviewerInfo(a));
         }
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SystemInfoServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SystemInfoServiceImpl.java
index 931605c..56a6a50 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SystemInfoServiceImpl.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SystemInfoServiceImpl.java
@@ -72,7 +72,7 @@
   }
 
   public void daemonHostKeys(final AsyncCallback<List<SshHostKey>> callback) {
-    final ArrayList<SshHostKey> r = new ArrayList<SshHostKey>(hostKeys.size());
+    final ArrayList<SshHostKey> r = new ArrayList<>(hostKeys.size());
     for (final HostKey hk : hostKeys) {
       String host = hk.getHost();
       if (host.startsWith("*:")) {
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountServiceImpl.java
index 90357ae..bdb0028 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountServiceImpl.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountServiceImpl.java
@@ -113,8 +113,7 @@
       final AsyncCallback<List<AccountProjectWatchInfo>> callback) {
     run(callback, new Action<List<AccountProjectWatchInfo>>() {
       public List<AccountProjectWatchInfo> run(ReviewDb db) throws OrmException {
-        final List<AccountProjectWatchInfo> r =
-            new ArrayList<AccountProjectWatchInfo>();
+        List<AccountProjectWatchInfo> r = new ArrayList<>();
 
         for (final AccountProjectWatch w : db.accountProjectWatches()
             .byAccount(getAccountId()).toList()) {
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/DeleteExternalIds.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/DeleteExternalIds.java
index 12bc761..1d45c7d 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/DeleteExternalIds.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/DeleteExternalIds.java
@@ -63,7 +63,7 @@
   public Set<AccountExternalId.Key> call() throws OrmException {
     final Map<AccountExternalId.Key, AccountExternalId> have = have();
 
-    List<AccountExternalId> toDelete = new ArrayList<AccountExternalId>();
+    List<AccountExternalId> toDelete = new ArrayList<>();
     for (AccountExternalId.Key k : keys) {
       final AccountExternalId id = have.get(k);
       if (id != null && id.canDelete()) {
@@ -86,7 +86,7 @@
       throws OrmException {
     Map<AccountExternalId.Key, AccountExternalId> r;
 
-    r = new HashMap<AccountExternalId.Key, AccountExternalId>();
+    r = new HashMap<>();
     for (AccountExternalId i : detailFactory.call()) {
       r.put(i.getKey(), i);
     }
@@ -94,7 +94,7 @@
   }
 
   private Set<AccountExternalId.Key> toKeySet(List<AccountExternalId> toDelete) {
-    Set<AccountExternalId.Key> r = new HashSet<AccountExternalId.Key>();
+    Set<AccountExternalId.Key> r = new HashSet<>();
     for (AccountExternalId i : toDelete) {
       r.add(i.getKey());
     }
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetDetailFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetDetailFactory.java
index fce8637..c4a8bb6 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetDetailFactory.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetDetailFactory.java
@@ -138,7 +138,7 @@
     }
 
     final List<Patch> patches = list.toPatchList(patchSet.getId());
-    final Map<Patch.Key, Patch> byKey = new HashMap<Patch.Key, Patch>();
+    final Map<Patch.Key, Patch> byKey = new HashMap<>();
     for (final Patch p : patches) {
       byKey.put(p.getKey(), p);
     }
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessFactory.java
index ee4439f..f0f93903 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessFactory.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessFactory.java
@@ -114,8 +114,8 @@
     }
 
     final RefControl metaConfigControl = pc.controlForRef(RefNames.REFS_CONFIG);
-    List<AccessSection> local = new ArrayList<AccessSection>();
-    Set<String> ownerOf = new HashSet<String>();
+    List<AccessSection> local = new ArrayList<>();
+    Set<String> ownerOf = new HashSet<>();
     Map<AccountGroup.UUID, Boolean> visibleGroups = new HashMap<>();
 
     for (AccessSection section : config.getAccessSections()) {
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessHandler.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessHandler.java
index b2b8bb3..52283b2 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessHandler.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessHandler.java
@@ -185,7 +185,7 @@
   }
 
   private static Set<String> scanSectionNames(ProjectConfig config) {
-    Set<String> names = new HashSet<String>();
+    Set<String> names = new HashSet<>();
     for (AccessSection section : config.getAccessSections()) {
       names.add(section.getName());
     }
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ReviewProjectAccess.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ReviewProjectAccess.java
index 6537a6b..51aa2c0 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ReviewProjectAccess.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ReviewProjectAccess.java
@@ -182,7 +182,7 @@
   private void insertAncestors(PatchSet.Id id, RevCommit src)
       throws OrmException {
     final int cnt = src.getParentCount();
-    List<PatchSetAncestor> toInsert = new ArrayList<PatchSetAncestor>(cnt);
+    List<PatchSetAncestor> toInsert = new ArrayList<>(cnt);
     for (int p = 0; p < cnt; p++) {
       PatchSetAncestor a;
 
diff --git a/gerrit-launcher/src/main/java/com/google/gerrit/launcher/GerritLauncher.java b/gerrit-launcher/src/main/java/com/google/gerrit/launcher/GerritLauncher.java
index 33a3534..474b284 100644
--- a/gerrit-launcher/src/main/java/com/google/gerrit/launcher/GerritLauncher.java
+++ b/gerrit-launcher/src/main/java/com/google/gerrit/launcher/GerritLauncher.java
@@ -50,7 +50,7 @@
     System.exit(mainImpl(argv));
   }
 
-  private static int mainImpl(final String argv[]) throws Exception {
+  public static int mainImpl(final String argv[]) throws Exception {
     if (argv.length == 0) {
       File me;
       try {
@@ -192,7 +192,7 @@
       throw e;
     }
 
-    final SortedMap<String, URL> jars = new TreeMap<String, URL>();
+    final SortedMap<String, URL> jars = new TreeMap<>();
     try {
       final ZipFile zf = new ZipFile(path);
       try {
@@ -220,7 +220,7 @@
 
     // The extension API needs to be its own ClassLoader, along
     // with a few of its dependencies. Try to construct this first.
-    List<URL> extapi = new ArrayList<URL>();
+    List<URL> extapi = new ArrayList<>();
     move(jars, "gerrit-extension-api-", extapi);
     move(jars, "guice-", extapi);
     move(jars, "javax.inject-1.jar", extapi);
@@ -592,7 +592,7 @@
   private static ClassLoader useDevClasspath()
       throws MalformedURLException, FileNotFoundException {
     File out = getDeveloperBuckOut();
-    List<URL> dirs = new ArrayList<URL>();
+    List<URL> dirs = new ArrayList<>();
     dirs.add(new File(new File(out, "eclipse"), "classes").toURI().toURL());
     ClassLoader cl = GerritLauncher.class.getClassLoader();
     for (URL u : ((URLClassLoader) cl).getURLs()) {
diff --git a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/SubIndex.java b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/SubIndex.java
index c36eade..4ee3bf4 100644
--- a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/SubIndex.java
+++ b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/SubIndex.java
@@ -107,6 +107,23 @@
         writer.getIndexWriter(), true, new SearcherFactory());
 
     notDoneNrtFutures = Sets.newConcurrentHashSet();
+
+    reopenThread = new ControlledRealTimeReopenThread<IndexSearcher>(
+        writer, searcherManager,
+        0.500 /* maximum stale age (seconds) */,
+        0.010 /* minimum stale age (seconds) */);
+    reopenThread.setName("NRT " + dirName);
+    reopenThread.setPriority(Math.min(
+        Thread.currentThread().getPriority() + 2,
+        Thread.MAX_PRIORITY));
+    reopenThread.setDaemon(true);
+
+    // This must be added after the reopen thread is created. The reopen thread
+    // adds its own listener which copies its internally last-refreshed
+    // generation to the searching generation. removeIfDone() depends on the
+    // searching generation being up to date when calling
+    // reopenThread.waitForGeneration(gen, 0), therefore the reopen thread's
+    // internal listener needs to be called first.
     searcherManager.addListener(new RefreshListener() {
       @Override
       public void beforeRefresh() throws IOException {
@@ -120,20 +137,25 @@
       }
     });
 
-    reopenThread = new ControlledRealTimeReopenThread<IndexSearcher>(
-        writer, searcherManager,
-        0.500 /* maximum stale age (seconds) */,
-        0.010 /* minimum stale age (seconds) */);
-    reopenThread.setName("NRT " + dirName);
-    reopenThread.setPriority(Math.min(
-        Thread.currentThread().getPriority() + 2,
-        Thread.MAX_PRIORITY));
-    reopenThread.setDaemon(true);
     reopenThread.start();
   }
 
   void close() {
     reopenThread.close();
+
+    // Closing the reopen thread sets its generation to Long.MAX_VALUE, but we
+    // still need to refresh the searcher manager to let pending NrtFutures
+    // know.
+    //
+    // Any futures created after this method (which may happen due to undefined
+    // shutdown ordering behavior) will finish immediately, even though they may
+    // not have flushed.
+    try {
+      searcherManager.maybeRefreshBlocking();
+    } catch (IOException e) {
+      log.warn("error finishing pending Lucene writes", e);
+    }
+
     try {
       writer.getIndexWriter().commit();
       try {
@@ -180,6 +202,9 @@
 
     NrtFuture(long gen) {
       this.gen = gen;
+      // Tell the reopen thread we are waiting on this generation so it uses the
+      // min stale time when refreshing.
+      isGenAvailableNowForCurrentSearcher();
     }
 
     @Override
@@ -218,7 +243,9 @@
 
     @Override
     public void addListener(Runnable listener, Executor executor) {
-      if (!isDone()) {
+      if (isGenAvailableNowForCurrentSearcher() && !isCancelled()) {
+        set(null);
+      } else if (!isDone()) {
         notDoneNrtFutures.add(this);
       }
       super.addListener(listener, executor);
diff --git a/gerrit-pgm/BUCK b/gerrit-pgm/BUCK
index d1c468f..f76fa4c 100644
--- a/gerrit-pgm/BUCK
+++ b/gerrit-pgm/BUCK
@@ -115,6 +115,7 @@
     '//lib/guice:guice-servlet',
     '//lib/jetty:server',
     '//lib/jetty:servlet',
+    '//lib/jetty:jmx',
     '//lib/jgit:jgit',
     '//lib/log:api',
     '//lib/log:log4j',
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/BaseInit.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/BaseInit.java
index 313408e..bacdd2d 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/BaseInit.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/BaseInit.java
@@ -185,7 +185,7 @@
   private SiteInit createSiteInit() {
     final ConsoleUI ui = getConsoleUI();
     final File sitePath = getSitePath();
-    final List<Module> m = new ArrayList<Module>();
+    final List<Module> m = new ArrayList<>();
 
     m.add(new InitModule(standalone, initDb));
     m.add(new AbstractModule() {
@@ -250,7 +250,7 @@
     }
 
     void upgradeSchema() throws OrmException {
-      final List<String> pruneList = new ArrayList<String>();
+      final List<String> pruneList = new ArrayList<>();
       schemaUpdater.update(new UpdateUI() {
         @Override
         public void message(String msg) {
@@ -316,7 +316,7 @@
   }
 
   private Injector createSysInjector(final SiteInit init) {
-    final List<Module> modules = new ArrayList<Module>();
+    final List<Module> modules = new ArrayList<>();
     modules.add(new AbstractModule() {
       @Override
       protected void configure() {
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java
index 9d10e66..1776a39 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java
@@ -303,13 +303,13 @@
   }
 
   private Injector createCfgInjector() {
-    final List<Module> modules = new ArrayList<Module>();
+    final List<Module> modules = new ArrayList<>();
     modules.add(new AuthConfigModule());
     return dbInjector.createChildInjector(modules);
   }
 
   private Injector createSysInjector() {
-    final List<Module> modules = new ArrayList<Module>();
+    final List<Module> modules = new ArrayList<>();
     modules.add(SchemaVersionCheck.module());
     modules.add(new LogFileCompressor.Module());
     modules.add(new WorkQueue.Module());
@@ -376,7 +376,7 @@
   }
 
   private Injector createSshInjector() {
-    final List<Module> modules = new ArrayList<Module>();
+    final List<Module> modules = new ArrayList<>();
     modules.add(sysInjector.getInstance(SshModule.class));
     if (!test) {
       modules.add(new SshHostKeyModule());
@@ -401,7 +401,7 @@
   }
 
   private Injector createWebInjector() {
-    final List<Module> modules = new ArrayList<Module>();
+    final List<Module> modules = new ArrayList<>();
     if (sshd) {
       modules.add(new ProjectQoSFilter.Module());
     }
@@ -429,7 +429,7 @@
   }
 
   private Injector createHttpdInjector() {
-    final List<Module> modules = new ArrayList<Module>();
+    final List<Module> modules = new ArrayList<>();
     modules.add(new JettyModule(new JettyEnv(webInjector)));
     return webInjector.createChildInjector(modules);
   }
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/LocalUsernamesToLowerCase.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/LocalUsernamesToLowerCase.java
index 323d7f28..d208a3c 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/LocalUsernamesToLowerCase.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/LocalUsernamesToLowerCase.java
@@ -70,7 +70,7 @@
       db.close();
     }
 
-    final List<Worker> workers = new ArrayList<Worker>(threads);
+    final List<Worker> workers = new ArrayList<>(threads);
     for (int tid = 0; tid < threads; tid++) {
       Worker t = new Worker();
       t.start();
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/PrologShell.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/PrologShell.java
index 4c66f0b..fa434a6 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/PrologShell.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/PrologShell.java
@@ -33,7 +33,7 @@
 
 public class PrologShell extends AbstractProgram {
   @Option(name = "-s", metaVar = "FILE.pl", usage = "file to load")
-  private List<String> fileName = new ArrayList<String>();
+  private List<String> fileName = new ArrayList<>();
 
   @Override
   public int run() {
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Reindex.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Reindex.java
index 1807e73..6d93dcd 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Reindex.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Reindex.java
@@ -43,7 +43,7 @@
 import com.google.gerrit.server.account.GroupIncludeCacheImpl;
 import com.google.gerrit.server.cache.CacheRemovalListener;
 import com.google.gerrit.server.cache.h2.DefaultCacheFactory;
-import com.google.gerrit.server.change.ChangeKindCache;
+import com.google.gerrit.server.change.ChangeKindCacheImpl;
 import com.google.gerrit.server.change.MergeabilityChecker;
 import com.google.gerrit.server.change.MergeabilityChecksExecutor;
 import com.google.gerrit.server.change.MergeabilityChecksExecutor.Priority;
@@ -219,6 +219,7 @@
         install(GroupIncludeCacheImpl.module());
         install(ProjectCacheImpl.module());
         install(SectionSortCache.module());
+        install(ChangeKindCacheImpl.module());
         factory(CapabilityControl.Factory.class);
         factory(ChangeData.Factory.class);
         factory(ProjectState.Factory.class);
@@ -251,7 +252,7 @@
           Key.get(new TypeLiteral<SchemaFactory<ReviewDb>>() {}));
       final List<ReviewDb> dbs = Collections.synchronizedList(
           Lists.<ReviewDb> newArrayListWithCapacity(threads + 1));
-      final ThreadLocal<ReviewDb> localDb = new ThreadLocal<ReviewDb>();
+      final ThreadLocal<ReviewDb> localDb = new ThreadLocal<>();
 
       bind(ReviewDb.class).toProvider(new Provider<ReviewDb>() {
         @Override
@@ -297,9 +298,6 @@
       DynamicSet.setOf(binder(), GitReferenceUpdatedListener.class);
       DynamicSet.setOf(binder(), CommitValidationListener.class);
       factory(CommitValidators.Factory.class);
-
-      install(ChangeKindCache.module());
-
       install(new GitModule());
       install(new NoteDbModule());
     }
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Rulec.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Rulec.java
index cabdc64..17a54d4 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Rulec.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Rulec.java
@@ -47,7 +47,7 @@
   private boolean quiet;
 
   @Argument(index = 0, multiValued = true, metaVar = "PROJECT", usage = "project to compile rules for")
-  private List<String> projectNames = new ArrayList<String>();
+  private List<String> projectNames = new ArrayList<>();
 
   private Injector dbInjector;
 
@@ -71,7 +71,7 @@
       }
     }).injectMembers(this);
 
-    LinkedHashSet<Project.NameKey> names = new LinkedHashSet<Project.NameKey>();
+    LinkedHashSet<Project.NameKey> names = new LinkedHashSet<>();
     for (String name : projectNames) {
       names.add(new Project.NameKey(name));
     }
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyServer.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyServer.java
index 6ba54c9..31d75f1 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyServer.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyServer.java
@@ -19,6 +19,7 @@
 
 import com.google.common.base.Charsets;
 import com.google.common.base.Objects;
+import com.google.common.base.Strings;
 import com.google.common.escape.Escaper;
 import com.google.common.html.HtmlEscapers;
 import com.google.common.io.ByteStreams;
@@ -38,6 +39,7 @@
 import com.google.inject.servlet.GuiceServletContextListener;
 
 import org.eclipse.jetty.http.HttpScheme;
+import org.eclipse.jetty.jmx.MBeanContainer;
 import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.ForwardedRequestCustomizer;
 import org.eclipse.jetty.server.Handler;
@@ -57,6 +59,7 @@
 import org.eclipse.jetty.servlet.ServletContextHandler;
 import org.eclipse.jetty.servlet.ServletHolder;
 import org.eclipse.jetty.util.BlockingArrayQueue;
+import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.resource.Resource;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.eclipse.jetty.util.thread.QueuedThreadPool;
@@ -74,6 +77,7 @@
 import java.io.InputStream;
 import java.io.InterruptedIOException;
 import java.io.PrintWriter;
+import java.lang.management.ManagementFactory;
 import java.net.MalformedURLException;
 import java.net.URI;
 import java.net.URISyntaxException;
@@ -103,16 +107,33 @@
 
   static class Lifecycle implements LifecycleListener {
     private final JettyServer server;
+    private final Config cfg;
 
     @Inject
-    Lifecycle(final JettyServer server) {
+    Lifecycle(final JettyServer server, @GerritServerConfig final Config cfg) {
       this.server = server;
+      this.cfg = cfg;
     }
 
     @Override
     public void start() {
       try {
+        String origUrl = cfg.getString("httpd", null, "listenUrl");
+        boolean rewrite = !Strings.isNullOrEmpty(origUrl)
+            && origUrl.endsWith(":0/");
         server.httpd.start();
+        if (rewrite) {
+          Connector con = server.httpd.getConnectors()[0];
+          if (con instanceof ServerConnector) {
+            @SuppressWarnings("resource")
+            ServerConnector serverCon = (ServerConnector)con;
+            String host = serverCon.getHost();
+            int port = serverCon.getLocalPort();
+            String url = String.format("http://%s:%d", host, port);
+            cfg.setString("gerrit", null, "canonicalWebUrl", url);
+            cfg.setString("httpd", null, "listenUrl", url);
+          }
+        }
       } catch (Exception e) {
         throw new IllegalStateException("Cannot start HTTP daemon", e);
       }
@@ -153,6 +174,13 @@
       handler.setHandler(app);
       app = handler;
     }
+    if (cfg.getBoolean("httpd", "registerMBeans", false)) {
+      MBeanContainer mbean =
+          new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
+      httpd.addEventListener(mbean);
+      httpd.addBean(Log.getRootLogger());
+      httpd.addBean(mbean);
+    }
 
     httpd.setHandler(app);
     httpd.setStopAtShutdown(false);
@@ -259,7 +287,7 @@
         } else {
           final URI r = u.parseServerAuthority();
           c.setHost(r.getHost());
-          c.setPort(0 < r.getPort() ? r.getPort() : defaultPort);
+          c.setPort(0 <= r.getPort() ? r.getPort() : defaultPort);
         }
       } catch (URISyntaxException e) {
         throw new IllegalArgumentException("Invalid httpd.listenurl " + u, e);
@@ -343,7 +371,7 @@
 
   private Handler makeContext(final JettyEnv env, final Config cfg)
       throws MalformedURLException, IOException {
-    final Set<String> paths = new HashSet<String>();
+    final Set<String> paths = new HashSet<>();
     for (URI u : listenURLs(cfg)) {
       String p = u.getPath();
       if (p == null || p.isEmpty()) {
@@ -355,7 +383,7 @@
       paths.add(p);
     }
 
-    final List<ContextHandler> all = new ArrayList<ContextHandler>();
+    final List<ContextHandler> all = new ArrayList<>();
     for (String path : paths) {
       all.add(makeContext(path, env, cfg));
     }
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitPluginStepsLoader.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitPluginStepsLoader.java
index 5584cf3..1b8600d 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitPluginStepsLoader.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitPluginStepsLoader.java
@@ -54,7 +54,7 @@
 
   public Collection<InitStep> getInitSteps() {
     List<File> jars = scanJarsInPluginsDirectory();
-    ArrayList<InitStep> pluginsInitSteps = new ArrayList<InitStep>();
+    ArrayList<InitStep> pluginsInitSteps = new ArrayList<>();
 
     for (File jar : jars) {
       InitStep init = loadInitStep(jar);
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/Section.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/Section.java
index bbb1d9f..5cce4a2 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/Section.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/Section.java
@@ -55,7 +55,7 @@
   }
 
   public void set(final String name, final String value) {
-    final ArrayList<String> all = new ArrayList<String>();
+    final ArrayList<String> all = new ArrayList<>();
     all.addAll(Arrays.asList(flags.cfg.getStringList(section, subsection, name)));
 
     if (value != null) {
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java
index 85e33e6..892a8a5 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java
@@ -125,7 +125,7 @@
   }
 
   private static List<InitStep> stepsOf(final Injector injector) {
-    final ArrayList<InitStep> r = new ArrayList<InitStep>();
+    final ArrayList<InitStep> r = new ArrayList<>();
     for (Binding<InitStep> b : all(injector)) {
       r.add(b.getProvider().get());
     }
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/shell/JythonShell.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/shell/JythonShell.java
index 38f08c1..5b537ae 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/shell/JythonShell.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/shell/JythonShell.java
@@ -85,7 +85,7 @@
     } catch (IllegalAccessException e) {
       throw noInterpreter(e);
     }
-    injectedVariables = new ArrayList<String>();
+    injectedVariables = new ArrayList<>();
     set("Shell", this);
   }
 
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/RuntimeShutdown.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/RuntimeShutdown.java
index c00ad7f..40aaa75 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/RuntimeShutdown.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/RuntimeShutdown.java
@@ -46,7 +46,7 @@
     private static final Logger log =
         LoggerFactory.getLogger(ShutdownCallback.class);
 
-    private final List<Runnable> tasks = new ArrayList<Runnable>();
+    private final List<Runnable> tasks = new ArrayList<>();
     private boolean shutdownStarted;
     private boolean shutdownComplete;
 
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteProgram.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteProgram.java
index daef562..3c60510 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteProgram.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteProgram.java
@@ -90,7 +90,7 @@
   /** @return provides database connectivity and site path. */
   protected Injector createDbInjector(final DataSourceProvider.Context context) {
     final File sitePath = getSitePath();
-    final List<Module> modules = new ArrayList<Module>();
+    final List<Module> modules = new ArrayList<>();
 
     Module sitePathModule = new AbstractModule() {
       @Override
diff --git a/gerrit-plugin-gwt-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml b/gerrit-plugin-gwt-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml
index f619f91..3fa83f4 100644
--- a/gerrit-plugin-gwt-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml
+++ b/gerrit-plugin-gwt-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml
@@ -25,7 +25,7 @@
       <defaultValue>http://code.google.com/p/gerrit/</defaultValue>
     </requiredProperty>
     <requiredProperty key="Gwt-Version">
-      <defaultValue>2.5.1</defaultValue>
+      <defaultValue>2.6.0</defaultValue>
     </requiredProperty>
 
     <requiredProperty key="gerritApiVersion">
diff --git a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/HelloMenu.java b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/HelloMenu.java
index 0baa044..f3c8dea 100644
--- a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/HelloMenu.java
+++ b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/HelloMenu.java
@@ -27,7 +27,7 @@
 
   @Inject
   public HelloMenu(@PluginName String pluginName) {
-    menuEntries = new ArrayList<TopMenu.MenuEntry>();
+    menuEntries = new ArrayList<>();
     menuEntries.add(new MenuEntry("Hello", Collections
         .singletonList(new MenuItem("Hello Screen", "#/x/" + pluginName, ""))));
   }
diff --git a/gerrit-plugin-gwtui/BUCK b/gerrit-plugin-gwtui/BUCK
index 0b87bb1..d256049 100644
--- a/gerrit-plugin-gwtui/BUCK
+++ b/gerrit-plugin-gwtui/BUCK
@@ -52,7 +52,7 @@
   title = 'Gerrit Review GWT Extension API Documentation',
   pkg = 'com.google.gerrit',
   paths = ['src/main/java'] + COMMON,
-  srcs = SRCS + glob(COMMON),
+  srcs = SRCS,
   deps = DEPS + ['//gerrit-gwtui-common:client-lib2'],
   visibility = ['PUBLIC'],
 )
diff --git a/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/Plugin.java b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/Plugin.java
index 41c03a2..046488d 100644
--- a/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/Plugin.java
+++ b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/Plugin.java
@@ -50,6 +50,10 @@
   public final native void refresh()
   /*-{ return this.refresh() }-*/;
 
+  /** Refresh Gerrit's menu bar. */
+  public final native void refreshMenuBar()
+  /*-{ return this.refreshMenuBar() }-*/;
+
   /** Show message in Gerrit's ErrorDialog. */
   public final native void showError(String message)
   /*-{ return this.showError(message) }-*/;
diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrettyFormatter.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrettyFormatter.java
index d4aef2a..ed42f10 100644
--- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrettyFormatter.java
+++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrettyFormatter.java
@@ -125,7 +125,7 @@
   public void format(SparseFileContent src) {
     content = new SparseFileContent();
     content.setSize(src.size());
-    trailingEdits = new HashSet<Integer>();
+    trailingEdits = new HashSet<>();
 
     String html = toHTML(src);
 
@@ -365,7 +365,7 @@
     // in the source. That simplifies our loop below because we'll never
     // run off the end of the edit list.
     //
-    List<Edit> edits = new ArrayList<Edit>(this.edits.size() + 1);
+    List<Edit> edits = new ArrayList<>(this.edits.size() + 1);
     edits.addAll(this.edits);
     edits.add(new Edit(src.size(), src.size()));
 
diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/SparseFileContent.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/SparseFileContent.java
index aa08af0..b6e3bf9 100644
--- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/SparseFileContent.java
+++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/SparseFileContent.java
@@ -29,7 +29,7 @@
   private transient int currentRangeIdx;
 
   public SparseFileContent() {
-    ranges = new ArrayList<Range>();
+    ranges = new ArrayList<>();
   }
 
   public int size() {
@@ -222,7 +222,7 @@
 
   public SparseFileContent apply(SparseFileContent a, List<Edit> edits) {
     EditList list = new EditList(edits, size, a.size(), size);
-    ArrayList<String> lines = new ArrayList<String>(size);
+    ArrayList<String> lines = new ArrayList<>(size);
     for (final EditList.Hunk hunk : list.getHunks()) {
       while (hunk.next()) {
         if (hunk.isContextLine()) {
@@ -277,7 +277,7 @@
 
     private Range(final int b) {
       base = b;
-      lines = new ArrayList<String>();
+      lines = new ArrayList<>();
     }
 
     protected Range() {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHookRunner.java b/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHookRunner.java
index 17940c0..1819272 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHookRunner.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHookRunner.java
@@ -156,7 +156,7 @@
     /** Listeners to receive changes as they happen (limited by visibility
      *  of holder's user). */
     private final Map<ChangeListener, ChangeListenerHolder> listeners =
-      new ConcurrentHashMap<ChangeListener, ChangeListenerHolder>();
+        new ConcurrentHashMap<>();
 
     /** Listeners to receive all changes as they happen. */
     private final DynamicSet<ChangeListener> unrestrictedListeners;
@@ -320,7 +320,7 @@
     public HookResult doRefUpdateHook(final Project project, final String refname,
         final Account uploader, final ObjectId oldId, final ObjectId newId) {
 
-      final List<String> args = new ArrayList<String>();
+      final List<String> args = new ArrayList<>();
       addArg(args, "--project", project.getName());
       addArg(args, "--refname", refname);
       addArg(args, "--uploader", getDisplayName(uploader));
@@ -349,16 +349,18 @@
           final ReviewDb db) throws OrmException {
         final PatchSetCreatedEvent event = new PatchSetCreatedEvent();
         final AccountState uploader = accountCache.get(patchSet.getUploader());
+        final AccountState owner = accountCache.get(change.getOwner());
 
         event.change = eventFactory.asChangeAttribute(change);
         event.patchSet = eventFactory.asPatchSetAttribute(patchSet);
         event.uploader = eventFactory.asAccountAttribute(uploader.getAccount());
         fireEvent(change, event, db);
 
-        final List<String> args = new ArrayList<String>();
+        final List<String> args = new ArrayList<>();
         addArg(args, "--change", event.change.id);
         addArg(args, "--is-draft", patchSet.isDraft() ? "true" : "false");
         addArg(args, "--change-url", event.change.url);
+        addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
         addArg(args, "--project", event.change.project);
         addArg(args, "--branch", event.change.branch);
         addArg(args, "--topic", event.change.topic);
@@ -373,15 +375,17 @@
           final ReviewDb db) throws OrmException {
         final DraftPublishedEvent event = new DraftPublishedEvent();
         final AccountState uploader = accountCache.get(patchSet.getUploader());
+        final AccountState owner = accountCache.get(change.getOwner());
 
         event.change = eventFactory.asChangeAttribute(change);
         event.patchSet = eventFactory.asPatchSetAttribute(patchSet);
         event.uploader = eventFactory.asAccountAttribute(uploader.getAccount());
         fireEvent(change, event, db);
 
-        final List<String> args = new ArrayList<String>();
+        final List<String> args = new ArrayList<>();
         addArg(args, "--change", event.change.id);
         addArg(args, "--change-url", event.change.url);
+        addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
         addArg(args, "--project", event.change.project);
         addArg(args, "--branch", event.change.branch);
         addArg(args, "--topic", event.change.topic);
@@ -396,6 +400,7 @@
           final PatchSet patchSet, final String comment, final Map<String, Short> approvals,
           final ReviewDb db) throws OrmException {
         final CommentAddedEvent event = new CommentAddedEvent();
+        final AccountState owner = accountCache.get(change.getOwner());
 
         event.change = eventFactory.asChangeAttribute(change);
         event.author =  eventFactory.asAccountAttribute(account);
@@ -413,10 +418,11 @@
 
         fireEvent(change, event, db);
 
-        final List<String> args = new ArrayList<String>();
+        final List<String> args = new ArrayList<>();
         addArg(args, "--change", event.change.id);
         addArg(args, "--is-draft", patchSet.isDraft() ? "true" : "false");
         addArg(args, "--change-url", event.change.url);
+        addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
         addArg(args, "--project", event.change.project);
         addArg(args, "--branch", event.change.branch);
         addArg(args, "--topic", event.change.topic);
@@ -436,15 +442,17 @@
     public void doChangeMergedHook(final Change change, final Account account,
           final PatchSet patchSet, final ReviewDb db) throws OrmException {
         final ChangeMergedEvent event = new ChangeMergedEvent();
+        final AccountState owner = accountCache.get(change.getOwner());
 
         event.change = eventFactory.asChangeAttribute(change);
         event.submitter = eventFactory.asAccountAttribute(account);
         event.patchSet = eventFactory.asPatchSetAttribute(patchSet);
         fireEvent(change, event, db);
 
-        final List<String> args = new ArrayList<String>();
+        final List<String> args = new ArrayList<>();
         addArg(args, "--change", event.change.id);
         addArg(args, "--change-url", event.change.url);
+        addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
         addArg(args, "--project", event.change.project);
         addArg(args, "--branch", event.change.branch);
         addArg(args, "--topic", event.change.topic);
@@ -458,6 +466,7 @@
           final PatchSet patchSet, final String reason,
           final ReviewDb db) throws OrmException {
         final MergeFailedEvent event = new MergeFailedEvent();
+        final AccountState owner = accountCache.get(change.getOwner());
 
         event.change = eventFactory.asChangeAttribute(change);
         event.submitter = eventFactory.asAccountAttribute(account);
@@ -465,9 +474,10 @@
         event.reason = reason;
         fireEvent(change, event, db);
 
-        final List<String> args = new ArrayList<String>();
+        final List<String> args = new ArrayList<>();
         addArg(args, "--change", event.change.id);
         addArg(args, "--change-url", event.change.url);
+        addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
         addArg(args, "--project", event.change.project);
         addArg(args, "--branch", event.change.branch);
         addArg(args, "--topic", event.change.topic);
@@ -482,6 +492,7 @@
           final PatchSet patchSet, final String reason, final ReviewDb db)
           throws OrmException {
         final ChangeAbandonedEvent event = new ChangeAbandonedEvent();
+        final AccountState owner = accountCache.get(change.getOwner());
 
         event.change = eventFactory.asChangeAttribute(change);
         event.abandoner = eventFactory.asAccountAttribute(account);
@@ -489,9 +500,10 @@
         event.reason = reason;
         fireEvent(change, event, db);
 
-        final List<String> args = new ArrayList<String>();
+        final List<String> args = new ArrayList<>();
         addArg(args, "--change", event.change.id);
         addArg(args, "--change-url", event.change.url);
+        addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
         addArg(args, "--project", event.change.project);
         addArg(args, "--branch", event.change.branch);
         addArg(args, "--topic", event.change.topic);
@@ -506,6 +518,7 @@
           final PatchSet patchSet, final String reason, final ReviewDb db)
           throws OrmException {
         final ChangeRestoredEvent event = new ChangeRestoredEvent();
+        final AccountState owner = accountCache.get(change.getOwner());
 
         event.change = eventFactory.asChangeAttribute(change);
         event.restorer = eventFactory.asAccountAttribute(account);
@@ -513,9 +526,10 @@
         event.reason = reason;
         fireEvent(change, event, db);
 
-        final List<String> args = new ArrayList<String>();
+        final List<String> args = new ArrayList<>();
         addArg(args, "--change", event.change.id);
         addArg(args, "--change-url", event.change.url);
+        addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
         addArg(args, "--project", event.change.project);
         addArg(args, "--branch", event.change.branch);
         addArg(args, "--topic", event.change.topic);
@@ -539,7 +553,7 @@
       event.refUpdate = eventFactory.asRefUpdateAttribute(oldId, newId, refName);
       fireEvent(refName, event);
 
-      final List<String> args = new ArrayList<String>();
+      final List<String> args = new ArrayList<>();
       addArg(args, "--oldrev", event.refUpdate.oldRev);
       addArg(args, "--newrev", event.refUpdate.newRev);
       addArg(args, "--refname", event.refUpdate.refName);
@@ -554,15 +568,17 @@
     public void doReviewerAddedHook(final Change change, final Account account,
         final PatchSet patchSet, final ReviewDb db) throws OrmException {
       final ReviewerAddedEvent event = new ReviewerAddedEvent();
+      final AccountState owner = accountCache.get(change.getOwner());
 
       event.change = eventFactory.asChangeAttribute(change);
       event.patchSet = eventFactory.asPatchSetAttribute(patchSet);
       event.reviewer = eventFactory.asAccountAttribute(account);
       fireEvent(change, event, db);
 
-      final List<String> args = new ArrayList<String>();
+      final List<String> args = new ArrayList<>();
       addArg(args, "--change", event.change.id);
       addArg(args, "--change-url", event.change.url);
+      addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
       addArg(args, "--project", event.change.project);
       addArg(args, "--branch", event.change.branch);
       addArg(args, "--reviewer", getDisplayName(account));
@@ -574,14 +590,16 @@
         final String oldTopic, final ReviewDb db)
             throws OrmException {
       final TopicChangedEvent event = new TopicChangedEvent();
+      final AccountState owner = accountCache.get(change.getOwner());
 
       event.change = eventFactory.asChangeAttribute(change);
       event.changer = eventFactory.asAccountAttribute(account);
       event.oldTopic = oldTopic;
       fireEvent(change, event, db);
 
-      final List<String> args = new ArrayList<String>();
+      final List<String> args = new ArrayList<>();
       addArg(args, "--change", event.change.id);
+      addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
       addArg(args, "--project", event.change.project);
       addArg(args, "--branch", event.change.branch);
       addArg(args, "--changer", getDisplayName(account));
@@ -593,7 +611,7 @@
 
     public void doClaSignupHook(Account account, ContributorAgreement cla) {
       if (account != null) {
-        final List<String> args = new ArrayList<String>();
+        final List<String> args = new ArrayList<>();
         addArg(args, "--submitter", getDisplayName(account));
         addArg(args, "--user-id", account.getId().toString());
         addArg(args, "--cla-name", cla.getName());
@@ -721,7 +739,7 @@
     }
 
     SyncHookTask syncHook = new SyncHookTask(project, hook, args);
-    FutureTask<HookResult> task = new FutureTask<HookResult>(syncHook);
+    FutureTask<HookResult> task = new FutureTask<>(syncHook);
 
     syncHookThreadPool.execute(task);
 
@@ -781,7 +799,7 @@
       HookResult result = null;
       try {
 
-        final List<String> argv = new ArrayList<String>(1 + args.size());
+        final List<String> argv = new ArrayList<>(1 + args.size());
         argv.add(hook.getAbsolutePath());
         argv.addAll(args);
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/rules/PrologCompiler.java b/gerrit-server/src/main/java/com/google/gerrit/rules/PrologCompiler.java
index 8202ac2..7f6bff4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/rules/PrologCompiler.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/rules/PrologCompiler.java
@@ -154,13 +154,13 @@
     }
 
     DiagnosticCollector<JavaFileObject> diagnostics =
-        new DiagnosticCollector<JavaFileObject>();
+        new DiagnosticCollector<>();
     StandardJavaFileManager fileManager =
         compiler.getStandardFileManager(diagnostics, null, null);
     try {
       Iterable<? extends JavaFileObject> compilationUnits = fileManager
         .getJavaFileObjectsFromFiles(getAllFiles(tempDir, ".java"));
-      ArrayList<String> options = new ArrayList<String>();
+      ArrayList<String> options = new ArrayList<>();
       String classpath = getMyClasspath();
       if (classpath != null) {
         options.add("-classpath");
@@ -270,7 +270,7 @@
   }
 
   private List<File> getAllFiles(File dir, String extension) {
-    ArrayList<File> fileList = new ArrayList<File>();
+    ArrayList<File> fileList = new ArrayList<>();
     getAllFiles(dir, extension, fileList);
     return fileList;
   }
@@ -287,7 +287,7 @@
   }
 
   private List<String> getRelativePaths(File dir, String extension) {
-    ArrayList<String> pathList = new ArrayList<String>();
+    ArrayList<String> pathList = new ArrayList<>();
     getRelativePaths(dir, extension, "", pathList);
     return pathList;
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/rules/PrologEnvironment.java b/gerrit-server/src/main/java/com/google/gerrit/rules/PrologEnvironment.java
index 234a0e7b..029a5d7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/rules/PrologEnvironment.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/rules/PrologEnvironment.java
@@ -73,8 +73,8 @@
     setMaxArity(MAX_ARITY);
     setEnabled(EnumSet.allOf(Prolog.Feature.class), false);
     args = a;
-    storedValues = new HashMap<StoredValue<Object>, Object>();
-    cleanup = new LinkedList<Runnable>();
+    storedValues = new HashMap<>();
+    cleanup = new LinkedList<>();
   }
 
   public Args getArgs() {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/rules/RulesCache.java b/gerrit-server/src/main/java/com/google/gerrit/rules/RulesCache.java
index 4a3cd9a..e677b53 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/rules/RulesCache.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/rules/RulesCache.java
@@ -80,11 +80,10 @@
   private static final List<String> PACKAGE_LIST = ImmutableList.of(
       Prolog.BUILTIN, "gerrit");
 
-  private final Map<ObjectId, MachineRef> machineCache =
-      new HashMap<ObjectId, MachineRef>();
+  private final Map<ObjectId, MachineRef> machineCache = new HashMap<>();
 
   private final ReferenceQueue<PrologMachineCopy> dead =
-      new ReferenceQueue<PrologMachineCopy>();
+      new ReferenceQueue<>();
 
   private static final class MachineRef extends WeakReference<PrologMachineCopy> {
     final ObjectId key;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/rules/StoredValue.java b/gerrit-server/src/main/java/com/google/gerrit/rules/StoredValue.java
index e17346b..132360b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/rules/StoredValue.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/rules/StoredValue.java
@@ -25,12 +25,12 @@
 public class StoredValue<T> {
   /** Construct a new unique key that does not match any other key. */
   public static <T> StoredValue<T> create() {
-    return new StoredValue<T>();
+    return new StoredValue<>();
   }
 
   /** Construct a key based on a Java Class object, useful for singletons. */
   public static <T> StoredValue<T> create(Class<T> clazz) {
-    return new StoredValue<T>(clazz);
+    return new StoredValue<>(clazz);
   }
 
   private final Object key;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalCopier.java b/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalCopier.java
index 14aa2e3..e68b29c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalCopier.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalCopier.java
@@ -81,6 +81,11 @@
     db.patchSetApprovals().insert(getForPatchSet(db, ctl, ps));
   }
 
+  Iterable<PatchSetApproval> getForPatchSet(ReviewDb db,
+      ChangeControl ctl, PatchSet.Id psId) throws OrmException {
+    return getForPatchSet(db, ctl, db.patchSets().get(psId));
+  }
+
   private Iterable<PatchSetApproval> getForPatchSet(ReviewDb db,
       ChangeControl ctl, PatchSet ps) throws OrmException {
     ChangeData cd = changeDataFactory.create(db, ctl);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalsUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalsUtil.java
index b648548..64b5169 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalsUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalsUtil.java
@@ -43,6 +43,7 @@
 import com.google.gerrit.server.notedb.ChangeUpdate;
 import com.google.gerrit.server.notedb.NotesMigration;
 import com.google.gerrit.server.notedb.ReviewerState;
+import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.util.TimeUtil;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
@@ -90,11 +91,14 @@
   }
 
   private final NotesMigration migration;
+  private final ApprovalCopier copier;
 
   @VisibleForTesting
   @Inject
-  public ApprovalsUtil(NotesMigration migration) {
+  public ApprovalsUtil(NotesMigration migration,
+      ApprovalCopier copier) {
     this.migration = migration;
+    this.copier = copier;
   }
 
   /**
@@ -225,23 +229,22 @@
     return notes.load().getApprovals();
   }
 
-  public List<PatchSetApproval> byPatchSet(ReviewDb db, ChangeNotes notes,
+  public Iterable<PatchSetApproval> byPatchSet(ReviewDb db, ChangeControl ctl,
       PatchSet.Id psId) throws OrmException {
     if (!migration.readPatchSetApprovals()) {
       return sortApprovals(db.patchSetApprovals().byPatchSet(psId));
     }
-    return notes.load().getApprovals().get(psId);
+    return copier.getForPatchSet(db, ctl, psId);
   }
 
-  public List<PatchSetApproval> byPatchSetUser(ReviewDb db,
-      ChangeNotes notes, PatchSet.Id psId, Account.Id accountId)
+  public Iterable<PatchSetApproval> byPatchSetUser(ReviewDb db,
+      ChangeControl ctl, PatchSet.Id psId, Account.Id accountId)
       throws OrmException {
     if (!migration.readPatchSetApprovals()) {
       return sortApprovals(
           db.patchSetApprovals().byPatchSetUser(psId, accountId));
     }
-    return ImmutableList.copyOf(
-        filterApprovals(byPatchSet(db, notes, psId), accountId));
+    return filterApprovals(byPatchSet(db, ctl, psId), accountId);
   }
 
   public PatchSetApproval getSubmitter(ReviewDb db, ChangeNotes notes,
@@ -250,7 +253,8 @@
       return null;
     }
     try {
-      return getSubmitter(c, byPatchSet(db, notes, c));
+      // Submit approval is never copied, so bypass expensive byPatchSet call.
+      return getSubmitter(c, byChange(db, notes).get(c));
     } catch (OrmException e) {
       return null;
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java
index 939be28..68a62a1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java
@@ -147,7 +147,7 @@
   public static void insertAncestors(ReviewDb db, PatchSet.Id id, RevCommit src)
       throws OrmException {
     int cnt = src.getParentCount();
-    List<PatchSetAncestor> toInsert = new ArrayList<PatchSetAncestor>(cnt);
+    List<PatchSetAncestor> toInsert = new ArrayList<>(cnt);
     for (int p = 0; p < cnt; p++) {
       PatchSetAncestor a =
           new PatchSetAncestor(new PatchSetAncestor.Id(id, p + 1));
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/MimeUtilFileTypeRegistry.java b/gerrit-server/src/main/java/com/google/gerrit/server/MimeUtilFileTypeRegistry.java
index ff46b00..5263c6b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/MimeUtilFileTypeRegistry.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/MimeUtilFileTypeRegistry.java
@@ -94,7 +94,7 @@
 
   @SuppressWarnings("unchecked")
   public MimeType getMimeType(final String path, final byte[] content) {
-    Set<MimeType> mimeTypes = new HashSet<MimeType>();
+    Set<MimeType> mimeTypes = new HashSet<>();
     if (content != null && content.length > 0) {
       try {
         mimeTypes.addAll(mimeUtil.getMimeTypes(content));
@@ -112,7 +112,7 @@
       return MimeUtil2.UNKNOWN_MIME_TYPE;
     }
 
-    final List<MimeType> types = new ArrayList<MimeType>(mimeTypes);
+    final List<MimeType> types = new ArrayList<>(mimeTypes);
     Collections.sort(types, new Comparator<MimeType>() {
       @Override
       public int compare(MimeType a, MimeType b) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/RequestCleanup.java b/gerrit-server/src/main/java/com/google/gerrit/server/RequestCleanup.java
index d836646..b8c0888 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/RequestCleanup.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/RequestCleanup.java
@@ -32,7 +32,7 @@
   private static final Logger log =
       LoggerFactory.getLogger(RequestCleanup.class);
 
-  private final List<Runnable> cleanup = new LinkedList<Runnable>();
+  private final List<Runnable> cleanup = new LinkedList<>();
   private boolean ran;
 
   /** Register a task to be completed after the request ends. */
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/access/ListAccess.java b/gerrit-server/src/main/java/com/google/gerrit/server/access/ListAccess.java
index 8ff4e03..5d651ae 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/access/ListAccess.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/access/ListAccess.java
@@ -157,8 +157,7 @@
           pc.controlForRef(RefNames.REFS_CONFIG);
       local = Maps.newHashMap();
       ownerOf = Sets.newHashSet();
-      Map<AccountGroup.UUID, Boolean> visibleGroups =
-          new HashMap<AccountGroup.UUID, Boolean>();
+      Map<AccountGroup.UUID, Boolean> visibleGroups = new HashMap<>();
 
       for (AccessSection section : config.getAccessSections()) {
         String name = section.getName();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCacheImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCacheImpl.java
index 65b166b..a521840 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCacheImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCacheImpl.java
@@ -163,7 +163,7 @@
           Collections.unmodifiableCollection(db.accountExternalIds().byAccount(
               who).toList());
 
-      Set<AccountGroup.UUID> internalGroups = new HashSet<AccountGroup.UUID>();
+      Set<AccountGroup.UUID> internalGroups = new HashSet<>();
       for (AccountGroupMember g : db.accountGroupMembers().byAccount(who)) {
         final AccountGroup.Id groupId = g.getAccountGroupId();
         final AccountGroup group = groupCache.get(groupId);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountInfoCacheFactory.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountInfoCacheFactory.java
index e3cf0236..32781f0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountInfoCacheFactory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountInfoCacheFactory.java
@@ -36,7 +36,7 @@
   @Inject
   AccountInfoCacheFactory(final AccountCache accountCache) {
     this.accountCache = accountCache;
-    this.out = new HashMap<Account.Id, Account>();
+    this.out = new HashMap<>();
   }
 
   /**
@@ -66,7 +66,7 @@
    * Create an AccountInfoCache with the currently loaded Account entities.
    * */
   public AccountInfoCache create() {
-    final List<AccountInfo> r = new ArrayList<AccountInfo>(out.size());
+    final List<AccountInfo> r = new ArrayList<>(out.size());
     for (final Account a : out.values()) {
       r.add(new AccountInfo(a));
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java
index f068812..3ba3076 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java
@@ -200,8 +200,8 @@
     if (authConfig.isAllowGoogleAccountUpgrade()
         && who.isScheme(OpenIdUrls.URL_GOOGLE + "?")
         && who.getEmailAddress() != null) {
-      final List<AccountExternalId> openId = new ArrayList<AccountExternalId>();
-      final List<AccountExternalId> v1 = new ArrayList<AccountExternalId>();
+      final List<AccountExternalId> openId = new ArrayList<>();
+      final List<AccountExternalId> v1 = new ArrayList<>();
 
       for (final AccountExternalId extId : db.accountExternalIds()
           .byEmailAddress(who.getEmailAddress())) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountResolver.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountResolver.java
index 383ed05..cc66294 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountResolver.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountResolver.java
@@ -179,7 +179,7 @@
     // At this point we have no clue. Just perform a whole bunch of suggestions
     // and pray we come up with a reasonable result list.
     //
-    Set<Account.Id> result = new HashSet<Account.Id>();
+    Set<Account.Id> result = new HashSet<>();
     String a = nameOrEmail;
     String b = nameOrEmail + "\u9fa5";
     for (Account act : schema.get().accounts().suggestByFullName(a, b, 10)) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountState.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountState.java
index 488370e..66607e2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountState.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountState.java
@@ -74,7 +74,7 @@
    * validated by Gerrit directly.
    */
   public Set<String> getEmailAddresses() {
-    final Set<String> emails = new HashSet<String>();
+    final Set<String> emails = new HashSet<>();
     for (final AccountExternalId e : externalIds) {
       if (e.getEmailAddress() != null && !e.getEmailAddress().isEmpty()) {
         emails.add(e.getEmailAddress());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityCollection.java
index 0247dbe..f60c794 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityCollection.java
@@ -43,8 +43,7 @@
       section = new AccessSection(AccessSection.GLOBAL_CAPABILITIES);
     }
 
-    Map<String, List<PermissionRule>> tmp =
-        new HashMap<String, List<PermissionRule>>();
+    Map<String, List<PermissionRule>> tmp = new HashMap<>();
     for (Permission permission : section.getPermissions()) {
       for (PermissionRule rule : permission.getRules()) {
         if (!permission.getName().equals(GlobalCapability.EMAIL_REVIEWERS)
@@ -54,7 +53,7 @@
 
         List<PermissionRule> r = tmp.get(permission.getName());
         if (r == null) {
-          r = new ArrayList<PermissionRule>(2);
+          r = new ArrayList<>(2);
           tmp.put(permission.getName(), r);
         }
         r.add(rule);
@@ -62,8 +61,7 @@
     }
     configureDefaults(tmp, section);
 
-    Map<String, List<PermissionRule>> res =
-        new HashMap<String, List<PermissionRule>>();
+    Map<String, List<PermissionRule>> res = new HashMap<>();
     for (Map.Entry<String, List<PermissionRule>> e : tmp.entrySet()) {
       List<PermissionRule> rules = e.getValue();
       if (rules.size() == 1) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityControl.java
index aad22eb..8ccb731 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityControl.java
@@ -54,7 +54,7 @@
   CapabilityControl(ProjectCache projectCache, @Assisted CurrentUser currentUser) {
     capabilities = projectCache.getAllProjects().getCapabilityCollection();
     user = currentUser;
-    effective = new HashMap<String, List<PermissionRule>>();
+    effective = new HashMap<>();
   }
 
   /** Identity of the user the control will compute for. */
@@ -268,7 +268,7 @@
       return rules;
     }
 
-    List<PermissionRule> mine = new ArrayList<PermissionRule>(rules.size());
+    List<PermissionRule> mine = new ArrayList<>(rules.size());
     for (PermissionRule rule : rules) {
       if (match(groups, rule)) {
         mine.add(rule);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/ChangeUserName.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/ChangeUserName.java
index 1210906..6dd51e1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/ChangeUserName.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/ChangeUserName.java
@@ -141,7 +141,7 @@
   }
 
   private Collection<AccountExternalId> old() throws OrmException {
-    final Collection<AccountExternalId> r = new ArrayList<AccountExternalId>(1);
+    final Collection<AccountExternalId> r = new ArrayList<>(1);
     for (AccountExternalId i : db.accountExternalIds().byAccount(
         user.getAccountId())) {
       if (i.isScheme(SCHEME_USERNAME)) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetPreferences.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetPreferences.java
index e4f777a..401846a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetPreferences.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetPreferences.java
@@ -28,22 +28,27 @@
 import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadCommand;
 import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadScheme;
 import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.TimeFormat;
-import com.google.gerrit.reviewdb.client.RefNames;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
-import com.google.gerrit.server.project.ProjectCache;
-import com.google.gerrit.server.project.ProjectState;
+import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
+import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.Repository;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
 public class GetPreferences implements RestReadView<AccountResource> {
-  public static final String PREFERENCES = "preferences.config";
+  private static final Logger log = LoggerFactory.getLogger(GetPreferences.class);
+
   public static final String MY = "my";
   public static final String KEY_URL = "url";
   public static final String KEY_TARGET = "target";
@@ -51,19 +56,26 @@
 
   private final Provider<CurrentUser> self;
   private final Provider<ReviewDb> db;
-  private final ProjectState allUsers;
+  private final AllUsersName allUsersName;
+  private final GitRepositoryManager gitMgr;
 
   @Inject
   GetPreferences(Provider<CurrentUser> self, Provider<ReviewDb> db,
-      ProjectCache projectCache) {
+      AllUsersName allUsersName,
+      GitRepositoryManager gitMgr) {
     this.self = self;
     this.db = db;
-    this.allUsers = projectCache.getAllUsers();
+    this.allUsersName = allUsersName;
+    this.gitMgr = gitMgr;
   }
 
   @Override
   public PreferenceInfo apply(AccountResource rsrc)
-      throws AuthException, ResourceNotFoundException, OrmException {
+      throws AuthException,
+      ResourceNotFoundException,
+      OrmException,
+      IOException,
+      ConfigInvalidException {
     if (self.get() != rsrc.getUser()
         && !self.get().getCapabilities().canAdministrateServer()) {
       throw new AuthException("restricted to administrator");
@@ -72,8 +84,16 @@
     if (a == null) {
       throw new ResourceNotFoundException();
     }
-    return new PreferenceInfo(a.getGeneralPreferences(),
-        rsrc.getUser().getAccountId(), allUsers);
+
+    Repository git = gitMgr.openRepository(allUsersName);
+    try {
+      VersionedAccountPreferences p =
+          VersionedAccountPreferences.forUser(rsrc.getUser().getAccountId());
+      p.load(git);
+      return new PreferenceInfo(a.getGeneralPreferences(), p, git);
+    } finally {
+      git.close();
+    }
   }
 
   public static class PreferenceInfo {
@@ -96,13 +116,8 @@
     ChangeScreen changeScreen;
     List<TopMenu.MenuItem> my;
 
-    public PreferenceInfo(AccountGeneralPreferences p, Account.Id accountId,
-        ProjectState allUsers) {
-      this(p, RefNames.refsUsers(accountId), allUsers);
-    }
-
-    public PreferenceInfo(AccountGeneralPreferences p, String ref,
-        ProjectState allUsers) {
+    public PreferenceInfo(AccountGeneralPreferences p,
+        VersionedAccountPreferences v, Repository allUsers) {
       if (p != null) {
         changesPerPage = p.getMaximumPageSize();
         showSiteHeader = p.isShowSiteHeader() ? true : null;
@@ -120,16 +135,23 @@
         diffView = p.getDiffView();
         changeScreen = p.getChangeScreen();
       }
-      my = my(ref, allUsers);
+      my = my(v, allUsers);
     }
 
-    private List<TopMenu.MenuItem> my(String ref, ProjectState allUsers) {
-      List<TopMenu.MenuItem> my = my(allUsers, ref);
-      if (my.isEmpty() && !ref.equals(RefNames.REFS_USER + "default")) {
-        my = my(allUsers, RefNames.REFS_USER + "default");
+    private List<TopMenu.MenuItem> my(VersionedAccountPreferences v,
+        Repository allUsers) {
+      List<TopMenu.MenuItem> my = my(v);
+      if (my.isEmpty() && !v.isDefaults()) {
+        try {
+          VersionedAccountPreferences d = VersionedAccountPreferences.forDefault();
+          d.load(allUsers);
+          my = my(d);
+        } catch (ConfigInvalidException | IOException e) {
+          log.warn("cannot read default preferences", e);
+        }
       }
       if (my.isEmpty()) {
-        my.add(new TopMenu.MenuItem("Changes", "#/", null));
+        my.add(new TopMenu.MenuItem("Changes", "#/dashboard/self", null));
         my.add(new TopMenu.MenuItem("Drafts", "#/q/is:draft", null));
         my.add(new TopMenu.MenuItem("Draft Comments", "#/q/has:draft", null));
         my.add(new TopMenu.MenuItem("Watched Changes", "#/q/is:watched+is:open", null));
@@ -138,9 +160,9 @@
       return my;
     }
 
-    private List<TopMenu.MenuItem> my(ProjectState allUsers, String ref) {
+    private List<TopMenu.MenuItem> my(VersionedAccountPreferences v) {
       List<TopMenu.MenuItem> my = new ArrayList<>();
-      Config cfg = allUsers.getConfig(PREFERENCES, ref).get();
+      Config cfg = v.getConfig();
       for (String subsection : cfg.getSubsections(MY)) {
         String url = my(cfg, subsection, KEY_URL, "#/");
         String target = my(cfg, subsection, KEY_TARGET,
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupDetailFactory.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupDetailFactory.java
index 9b4f4df..889addf 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupDetailFactory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupDetailFactory.java
@@ -83,7 +83,7 @@
   }
 
   private List<AccountGroupMember> loadMembers() throws OrmException {
-    List<AccountGroupMember> members = new ArrayList<AccountGroupMember>();
+    List<AccountGroupMember> members = new ArrayList<>();
     for (final AccountGroupMember m : db.accountGroupMembers().byGroup(groupId)) {
       if (control.canSeeMember(m.getAccountId())) {
         aic.want(m.getAccountId());
@@ -117,7 +117,7 @@
   }
 
   private List<AccountGroupById> loadIncludes() throws OrmException {
-    List<AccountGroupById> groups = new ArrayList<AccountGroupById>();
+    List<AccountGroupById> groups = new ArrayList<>();
 
     for (final AccountGroupById m : db.accountGroupById().byGroup(groupId)) {
       if (control.canSeeGroup(m.getIncludeUUID())) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupMembers.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupMembers.java
index df5b2c1..3fe9d25 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupMembers.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupMembers.java
@@ -91,7 +91,7 @@
         projectControl.controlFor(project, currentUser).getProjectState()
             .getOwners();
 
-    final HashSet<Account> projectOwners = new HashSet<Account>();
+    final HashSet<Account> projectOwners = new HashSet<>();
     for (final AccountGroup.UUID ownerGroup : ownerGroups) {
       if (!seen.contains(ownerGroup)) {
         projectOwners.addAll(listAccounts(ownerGroup, project, seen));
@@ -107,7 +107,7 @@
     final GroupDetail groupDetail =
         groupDetailFactory.create(group.getId()).call();
 
-    final Set<Account> members = new HashSet<Account>();
+    final Set<Account> members = new HashSet<>();
     if (groupDetail.members != null) {
       for (final AccountGroupMember member : groupDetail.members) {
         members.add(accountCache.get(member.getAccountId()).getAccount());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformCreateGroup.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformCreateGroup.java
index ca1bf32..a54a97b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformCreateGroup.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformCreateGroup.java
@@ -126,10 +126,8 @@
 
   private void addMembers(final AccountGroup.Id groupId,
       final Collection<? extends Account.Id> members) throws OrmException {
-    final List<AccountGroupMember> memberships =
-        new ArrayList<AccountGroupMember>();
-    final List<AccountGroupMemberAudit> membershipsAudit =
-        new ArrayList<AccountGroupMemberAudit>();
+    List<AccountGroupMember> memberships = new ArrayList<>();
+    List<AccountGroupMemberAudit> membershipsAudit = new ArrayList<>();
     for (Account.Id accountId : members) {
       final AccountGroupMember membership =
           new AccountGroupMember(new AccountGroupMember.Key(accountId, groupId));
@@ -149,10 +147,8 @@
 
   private void addGroups(final AccountGroup.Id groupId,
       final Collection<? extends AccountGroup.UUID> groups) throws OrmException {
-    final List<AccountGroupById> includeList =
-      new ArrayList<AccountGroupById>();
-    final List<AccountGroupByIdAud> includesAudit =
-      new ArrayList<AccountGroupByIdAud>();
+    List<AccountGroupById> includeList = new ArrayList<>();
+    List<AccountGroupByIdAud> includesAudit = new ArrayList<>();
     for (AccountGroup.UUID includeUUID : groups) {
       final AccountGroupById groupInclude =
         new AccountGroupById(new AccountGroupById.Key(groupId, includeUUID));
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/SetPreferences.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/SetPreferences.java
index baf8eda..df985ec 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/SetPreferences.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/SetPreferences.java
@@ -18,7 +18,6 @@
 import static com.google.gerrit.server.account.GetPreferences.KEY_TARGET;
 import static com.google.gerrit.server.account.GetPreferences.KEY_URL;
 import static com.google.gerrit.server.account.GetPreferences.MY;
-import static com.google.gerrit.server.account.GetPreferences.PREFERENCES;
 
 import com.google.common.base.Strings;
 import com.google.gerrit.extensions.restapi.AuthException;
@@ -34,18 +33,16 @@
 import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadCommand;
 import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadScheme;
 import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.TimeFormat;
-import com.google.gerrit.reviewdb.client.RefNames;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.account.SetPreferences.Input;
+import com.google.gerrit.server.config.AllUsersName;
 import com.google.gerrit.server.git.MetaDataUpdate;
-import com.google.gerrit.server.git.ProjectLevelConfig;
-import com.google.gerrit.server.project.ProjectCache;
-import com.google.gerrit.server.project.ProjectState;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
+import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.Config;
 
 import java.io.IOException;
@@ -76,22 +73,22 @@
   private final AccountCache cache;
   private final ReviewDb db;
   private final MetaDataUpdate.User metaDataUpdateFactory;
-  private final ProjectState allUsers;
+  private final AllUsersName allUsersName;
 
   @Inject
   SetPreferences(Provider<CurrentUser> self, AccountCache cache, ReviewDb db,
-      MetaDataUpdate.User metaDataUpdateFactory, ProjectCache projectCache) {
+      MetaDataUpdate.User metaDataUpdateFactory, AllUsersName allUsersName) {
     this.self = self;
     this.cache = cache;
     this.db = db;
     this.metaDataUpdateFactory = metaDataUpdateFactory;
-    this.allUsers = projectCache.getAllUsers();
+    this.allUsersName = allUsersName;
   }
 
   @Override
   public GetPreferences.PreferenceInfo apply(AccountResource rsrc, Input i)
       throws AuthException, ResourceNotFoundException, OrmException,
-      IOException {
+      IOException, ConfigInvalidException {
     if (self.get() != rsrc.getUser()
         && !self.get().getCapabilities().canAdministrateServer()) {
       throw new AuthException("restricted to administrator");
@@ -102,6 +99,8 @@
 
     Account.Id accountId = rsrc.getUser().getAccountId();
     AccountGeneralPreferences p;
+    VersionedAccountPreferences versionedPrefs;
+    MetaDataUpdate md = metaDataUpdateFactory.create(allUsersName);
     db.accounts().beginTransaction(accountId);
     try {
       Account a = db.accounts().get(accountId);
@@ -109,6 +108,9 @@
         throw new ResourceNotFoundException();
       }
 
+      versionedPrefs = VersionedAccountPreferences.forUser(accountId);
+      versionedPrefs.load(md);
+
       p = a.getGeneralPreferences();
       if (p == null) {
         p = new AccountGeneralPreferences();
@@ -163,24 +165,21 @@
 
       db.accounts().update(Collections.singleton(a));
       db.commit();
-      storeMyMenus(accountId, i.my);
+      storeMyMenus(versionedPrefs, i.my);
+      versionedPrefs.commit(md);
       cache.evict(accountId);
+      return new GetPreferences.PreferenceInfo(
+          p, versionedPrefs,
+          md.getRepository());
     } finally {
+      md.close();
       db.rollback();
     }
-    return new GetPreferences.PreferenceInfo(p, accountId, allUsers);
   }
 
-  private void storeMyMenus(Account.Id accountId, List<TopMenu.MenuItem> my)
-      throws IOException {
-    storeMyMenus(RefNames.refsUsers(accountId), my);
-  }
-
-  public void storeMyMenus(String ref, List<TopMenu.MenuItem> my)
-      throws IOException {
-    ProjectLevelConfig prefsCfg =
-        allUsers.getConfig(PREFERENCES, ref);
-    Config cfg = prefsCfg.get();
+  public static void storeMyMenus(VersionedAccountPreferences prefs,
+      List<TopMenu.MenuItem> my) {
+    Config cfg = prefs.getConfig();
     if (my != null) {
       unsetSection(cfg, MY);
       for (TopMenu.MenuItem item : my) {
@@ -189,10 +188,6 @@
         set(cfg, item.name, KEY_ID, item.id);
       }
     }
-    MetaDataUpdate md =
-        metaDataUpdateFactory.create(allUsers.getProject().getNameKey());
-    md.setMessage("Updated preferences\n");
-    prefsCfg.commit(md);
   }
 
   private static void set(Config cfg, String section, String key, String val) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/VersionedAccountPreferences.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/VersionedAccountPreferences.java
new file mode 100644
index 0000000..c4d4b06
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/VersionedAccountPreferences.java
@@ -0,0 +1,75 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.account;
+
+import com.google.common.base.Strings;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.RefNames;
+import com.google.gerrit.server.git.VersionedMetaData;
+
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.Config;
+
+import java.io.IOException;
+
+/** Preferences for user accounts. */
+public class VersionedAccountPreferences extends VersionedMetaData {
+  private static final String REFS_USER_DEFAULT = RefNames.REFS_USER + "default";
+  private static final String PREFERENCES = "preferences.config";
+
+  public static VersionedAccountPreferences forUser(Account.Id id) {
+    return new VersionedAccountPreferences(RefNames.refsUsers(id));
+  }
+
+  public static VersionedAccountPreferences forDefault() {
+    return new VersionedAccountPreferences(REFS_USER_DEFAULT);
+  }
+
+  private final String ref;
+  private Config cfg;
+
+  private VersionedAccountPreferences(String ref) {
+    this.ref = ref;
+  }
+
+  public boolean isDefaults() {
+    return REFS_USER_DEFAULT.equals(getRefName());
+  }
+
+  @Override
+  protected String getRefName() {
+    return ref;
+  }
+
+  public Config getConfig() {
+    return cfg;
+  }
+
+  @Override
+  protected void onLoad() throws IOException, ConfigInvalidException {
+    cfg = readConfig(PREFERENCES);
+  }
+
+  @Override
+  protected boolean onSave(CommitBuilder commit) throws IOException,
+      ConfigInvalidException {
+    if (Strings.isNullOrEmpty(commit.getMessage())) {
+      commit.setMessage("Updated preferences\n");
+    }
+    saveConfig(PREFERENCES, cfg);
+    return true;
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/GerritApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/GerritApiImpl.java
index 33314d3..f7ca136 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/GerritApiImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/GerritApiImpl.java
@@ -20,7 +20,7 @@
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
-class GerritApiImpl implements GerritApi {
+class GerritApiImpl extends GerritApi.NotImplemented implements GerritApi {
   private final Provider<Changes> changes;
   private final Provider<Projects> projects;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
index 0bcfd65..8d4a0c9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
@@ -41,7 +41,7 @@
 import java.io.IOException;
 import java.util.EnumSet;
 
-class ChangeApiImpl implements ChangeApi {
+class ChangeApiImpl extends ChangeApi.NotImplemented implements ChangeApi {
   interface Factory {
     ChangeApiImpl create(ChangeResource change);
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeInfoMapper.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeInfoMapper.java
index 9d813fc..444676f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeInfoMapper.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeInfoMapper.java
@@ -89,6 +89,7 @@
     o.deletions = i.deletions;
     o.owner = fromAcountInfo(i.owner);
     o.currentRevision = i.currentRevision;
+    o._number = i._number;
   }
 
   private void mapMessages(ChangeJson.ChangeInfo i, ChangeInfo o) {
@@ -116,6 +117,7 @@
       lo.recommended = fromAcountInfo(li.recommended);
       lo.disliked = fromAcountInfo(li.disliked);
       lo.value = li.value;
+      lo.defaultValue = li.defaultValue;
       lo.optional = li.optional;
       lo.blocking = li.blocking;
       lo.values = li.values;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangesImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangesImpl.java
index fdd0817..27493dd 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangesImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangesImpl.java
@@ -26,7 +26,7 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 
-class ChangesImpl implements Changes {
+class ChangesImpl extends Changes.NotImplemented implements Changes {
   private final ChangesCollection changes;
   private final ChangeApiImpl.Factory api;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java
index fb82b7e..b965c18 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java
@@ -37,7 +37,7 @@
 
 import java.io.IOException;
 
-class RevisionApiImpl implements RevisionApi {
+class RevisionApiImpl extends RevisionApi.NotImplemented implements RevisionApi {
   interface Factory {
     RevisionApiImpl create(RevisionResource r);
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/BranchApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/BranchApiImpl.java
index 39166c3..f4dc67e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/BranchApiImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/BranchApiImpl.java
@@ -24,7 +24,7 @@
 
 import java.io.IOException;
 
-public class BranchApiImpl implements BranchApi {
+public class BranchApiImpl extends BranchApi.NotImplemented implements BranchApi {
   interface Factory {
     BranchApiImpl create(ProjectResource project, String ref);
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectApiImpl.java
index b2a1244..7f73a38 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectApiImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectApiImpl.java
@@ -36,7 +36,7 @@
 
 import java.io.IOException;
 
-public class ProjectApiImpl implements ProjectApi {
+public class ProjectApiImpl extends ProjectApi.NotImplemented implements ProjectApi {
   interface Factory {
     ProjectApiImpl create(ProjectResource project);
     ProjectApiImpl create(String name);
@@ -100,7 +100,7 @@
         throw new ResourceConflictException("Project already exists");
       }
       if (in.name != null && !name.equals(in.name)) {
-        throw new RestApiException("name must match input.name");
+        throw new BadRequestException("name must match input.name");
       }
       createProjectFactory.get().create(name)
           .apply(TopLevelResource.INSTANCE, in);
@@ -108,7 +108,7 @@
     } catch (BadRequestException | UnprocessableEntityException
         | ResourceNotFoundException | ProjectCreationFailedException
         | IOException e) {
-      throw new RestApiException("Cannot create project", e);
+      throw new RestApiException("Cannot create project: " + e.getMessage(), e);
     }
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectsImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectsImpl.java
index fc0396d..71f2730 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectsImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectsImpl.java
@@ -23,7 +23,7 @@
 
 import java.io.IOException;
 
-class ProjectsImpl implements Projects {
+class ProjectsImpl extends Projects.NotImplemented implements Projects {
   private final ProjectsCollection projects;
   private final ProjectApiImpl.Factory api;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/auth/NoSuchUserException.java b/gerrit-server/src/main/java/com/google/gerrit/server/auth/NoSuchUserException.java
new file mode 100644
index 0000000..acb90b9
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/auth/NoSuchUserException.java
@@ -0,0 +1,26 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.auth;
+
+import com.google.gerrit.server.account.AccountException;
+
+/** The user does not exist on the authentication server */
+public class NoSuchUserException extends AccountException {
+  private static final long serialVersionUID = 1L;
+
+  public NoSuchUserException(String username) {
+    super(String.format("No such user: %s", username));
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/Helper.java b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/Helper.java
index 63ef2e6..5a19814 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/Helper.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/Helper.java
@@ -20,6 +20,7 @@
 import com.google.gerrit.common.data.ParameterizedString;
 import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.server.account.AccountException;
+import com.google.gerrit.server.auth.NoSuchUserException;
 import com.google.gerrit.server.config.ConfigUtil;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.util.ssl.BlindSSLSocketFactory;
@@ -168,17 +169,17 @@
   LdapQuery.Result findAccount(final Helper.LdapSchema schema,
       final DirContext ctx, final String username) throws NamingException,
       AccountException {
-    final HashMap<String, String> params = new HashMap<String, String>();
+    final HashMap<String, String> params = new HashMap<>();
     params.put(LdapRealm.USERNAME, username);
 
-    final List<LdapQuery.Result> res = new ArrayList<LdapQuery.Result>();
+    final List<LdapQuery.Result> res = new ArrayList<>();
     for (LdapQuery accountQuery : schema.accountQueryList) {
       res.addAll(accountQuery.query(ctx, params));
     }
 
     switch (res.size()) {
       case 0:
-        throw new AccountException("No such user:" + username);
+        throw new NoSuchUserException(username);
 
       case 1:
         return res.get(0);
@@ -192,10 +193,10 @@
       final String username, LdapQuery.Result account)
       throws NamingException, AccountException {
     final LdapSchema schema = getSchema(ctx);
-    final Set<String> groupDNs = new HashSet<String>();
+    final Set<String> groupDNs = new HashSet<>();
 
     if (!schema.groupMemberQueryList.isEmpty()) {
-      final HashMap<String, String> params = new HashMap<String, String>();
+      final HashMap<String, String> params = new HashMap<>();
 
       if (account == null) {
         try {
@@ -243,7 +244,7 @@
       }
     }
 
-    final Set<AccountGroup.UUID> actual = new HashSet<AccountGroup.UUID>();
+    final Set<AccountGroup.UUID> actual = new HashSet<>();
     for (String dn : groupDNs) {
       actual.add(new AccountGroup.UUID(LDAP_UUID + dn));
     }
@@ -304,10 +305,10 @@
 
     LdapSchema(final DirContext ctx) {
       type = discoverLdapType(ctx);
-      groupMemberQueryList = new ArrayList<LdapQuery>();
-      accountQueryList = new ArrayList<LdapQuery>();
+      groupMemberQueryList = new ArrayList<>();
+      accountQueryList = new ArrayList<>();
 
-      final Set<String> accountAtts = new HashSet<String>();
+      final Set<String> accountAtts = new HashSet<>();
 
       // Group query
       //
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapGroupBackend.java b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapGroupBackend.java
index 26c1c7a..7731b7d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapGroupBackend.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapGroupBackend.java
@@ -227,7 +227,7 @@
         ParameterizedString filter = ParameterizedString.asis(
             schema.groupPattern.replace(GROUPNAME, name).toString());
         Set<String> returnAttrs =
-            new HashSet<String>(schema.groupName.getParameterNames());
+            new HashSet<>(schema.groupName.getParameterNames());
         Map<String, String> params = Collections.emptyMap();
         for (String groupBase : schema.groupBases) {
           LdapQuery query = new LdapQuery(
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapQuery.java b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapQuery.java
index 8a6dfeb..1f68011 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapQuery.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapQuery.java
@@ -69,7 +69,7 @@
     sc.setReturningAttributes(returnAttributes);
     res = ctx.search(base, pattern.getRawPattern(), pattern.bind(params), sc);
     try {
-      final List<Result> r = new ArrayList<Result>();
+      final List<Result> r = new ArrayList<>();
       try {
         while (res.hasMore()) {
           r.add(new Result(res.next()));
@@ -83,7 +83,7 @@
   }
 
   class Result {
-    private final Map<String, Attribute> atts = new HashMap<String, Attribute>();
+    private final Map<String, Attribute> atts = new HashMap<>();
 
     Result(final SearchResult sr) {
       if (returnAttributes != null) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapRealm.java b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapRealm.java
index 7cde019..84b5277 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapRealm.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapRealm.java
@@ -88,7 +88,7 @@
     this.membershipCache = membershipCache;
     this.config = config;
 
-    this.readOnlyAccountFields = new HashSet<Account.FieldName>();
+    this.readOnlyAccountFields = new HashSet<>();
 
     if (optdef(config, "accountFullName", "DEFAULT") != null) {
       readOnlyAccountFields.add(Account.FieldName.FULL_NAME);
@@ -174,7 +174,7 @@
       return null;
     }
 
-    final Map<String, String> values = new HashMap<String, String>();
+    final Map<String, String> values = new HashMap<>();
     for (final String name : m.attributes()) {
       values.put(name, m.get(name));
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/cache/CacheModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/cache/CacheModule.java
index c093380..2276def 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/cache/CacheModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/cache/CacheModule.java
@@ -83,8 +83,7 @@
     @SuppressWarnings("unchecked")
     Key<Cache<K, V>> key = (Key<Cache<K, V>>) Key.get(type, Names.named(name));
 
-    CacheProvider<K, V> m =
-        new CacheProvider<K, V>(this, name, keyType, valType);
+    CacheProvider<K, V> m = new CacheProvider<>(this, name, keyType, valType);
     bind(key).toProvider(m).asEagerSingleton();
     bind(ANY_CACHE).annotatedWith(Exports.named(name)).to(key);
     return m.maximumWeight(1024);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
index 42bfab2..231df63 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
@@ -41,7 +41,6 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.LinkedHashMultimap;
-import com.google.common.collect.ListMultimap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Multimap;
@@ -89,7 +88,6 @@
 import com.google.gerrit.server.patch.PatchSetInfoFactory;
 import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
 import com.google.gerrit.server.project.ChangeControl;
-import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.ProjectControl;
 import com.google.gerrit.server.query.change.ChangeData;
@@ -371,7 +369,7 @@
         ctrl = projectControls.get(cd.change().getProject())
             .controlFor(cd.change());
       }
-    } catch (NoSuchChangeException | ExecutionException e) {
+    } catch (ExecutionException e) {
       throw new OrmException(e);
     }
     lastControl = ctrl;
@@ -444,8 +442,7 @@
   private Map<String, LabelInfo> initLabels(ChangeData cd,
       LabelTypes labelTypes, boolean standard) throws OrmException {
     // Don't use Maps.newTreeMap(Comparator) due to OpenJDK bug 100167.
-    Map<String, LabelInfo> labels =
-        new TreeMap<String, LabelInfo>(labelTypes.nameComparator());
+    Map<String, LabelInfo> labels = new TreeMap<>(labelTypes.nameComparator());
     for (SubmitRecord rec : submitRecords(cd)) {
       if (rec.labels == null) {
         continue;
@@ -511,22 +508,18 @@
       return;
     }
 
-    // All users ever added, even if they can't vote on one or all labels.
+    // Include a user in the output for this label if either:
+    //  - They are an explicit reviewer.
+    //  - They ever voted on this change.
     Set<Account.Id> allUsers = Sets.newHashSet();
-    ListMultimap<PatchSet.Id, PatchSetApproval> allApprovals =
-        cd.approvals();
-    for (PatchSetApproval psa : allApprovals.values()) {
+    allUsers.addAll(cd.reviewers().values());
+    for (PatchSetApproval psa : cd.approvals().values()) {
       allUsers.add(psa.getAccountId());
     }
 
-    List<PatchSetApproval> currentList =
-        allApprovals.get(baseCtrl.getChange().currentPatchSetId());
-    // Most recent, normalized vote on each label for the current patch set by
-    // each user (may be 0).
     Table<Account.Id, String, PatchSetApproval> current = HashBasedTable.create(
         allUsers.size(), baseCtrl.getLabelTypes().getLabelTypes().size());
-    for (PatchSetApproval psa :
-        labelNormalizer.normalize(baseCtrl, currentList).getNormalized()) {
+    for (PatchSetApproval psa : cd.currentApprovals()) {
       current.put(psa.getAccountId(), psa.getLabel(), psa);
     }
 
@@ -547,9 +540,9 @@
           value = Integer.valueOf(psa.getValue());
           date = psa.getGranted();
         } else {
-          // Either the user cannot vote on this label, or there just wasn't a
-          // dummy approval for this label. Explicitly check whether the user
-          // can vote on this label.
+          // Either the user cannot vote on this label, or they were added as a
+          // reviewer but have not responded yet. Explicitly check whether the
+          // user can vote on this label.
           value = labelNormalizer.canVote(ctl, lt, accountId) ? 0 : null;
         }
         e.getValue().addApproval(approvalInfo(accountId, value, date));
@@ -579,8 +572,7 @@
     // would have done. These should really come from a stored submit record.
     //
     // Don't use Maps.newTreeMap(Comparator) due to OpenJDK bug 100167.
-    Map<String, LabelInfo> labels =
-        new TreeMap<String, LabelInfo>(labelTypes.nameComparator());
+    Map<String, LabelInfo> labels = new TreeMap<>(labelTypes.nameComparator());
     for (String name : labelNames) {
       LabelType type = labelTypes.byLabel(name);
       LabelInfo li = new LabelInfo();
@@ -638,6 +630,7 @@
   }
 
   private void setLabelValues(LabelType type, LabelInfo label) {
+    label.defaultValue = type.getDefaultValue();
     label.values = Maps.newLinkedHashMap();
     for (LabelValue v : type.getValues()) {
       label.values.put(v.formatValue(), v.getText());
@@ -1014,6 +1007,7 @@
     public Map<String, String> values;
 
     public Short value;
+    public Short defaultValue;
     public Boolean optional;
     public Boolean blocking;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeKindCache.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeKindCache.java
index f6e5773..0e0984d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeKindCache.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeKindCache.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2013 The Android Open Source Project
+// Copyright (C) 2014 The Android Open Source Project
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -14,32 +14,10 @@
 
 package com.google.gerrit.server.change;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.base.Objects;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
-import com.google.gerrit.server.cache.CacheModule;
-import com.google.gerrit.server.config.GerritServerConfig;
-import com.google.gerrit.server.git.MergeUtil;
 import com.google.gerrit.server.project.ProjectState;
-import com.google.inject.Inject;
-import com.google.inject.Module;
-import com.google.inject.Singleton;
-import com.google.inject.name.Named;
 
-import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.merge.ThreeWayMerger;
-import org.eclipse.jgit.revwalk.RevCommit;
-import org.eclipse.jgit.revwalk.RevWalk;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.util.concurrent.ExecutionException;
 
 /**
  * Cache of {@link ChangeKind} per commit.
@@ -47,149 +25,7 @@
  * This is immutable conditioned on the merge strategy (unless the JGit strategy
  * implementation changes, which might invalidate old entries).
  */
-public class ChangeKindCache {
-  private static final Logger log =
-      LoggerFactory.getLogger(ChangeKindCache.class);
-
-  private static final String ID_CACHE = "change_kind";
-
-  public static Module module() {
-    return new CacheModule() {
-      @Override
-      protected void configure() {
-        cache(ID_CACHE,
-            Key.class,
-            ChangeKind.class)
-          .maximumWeight(0)
-          .loader(Loader.class);
-      }
-    };
-  }
-
-  public static class Key implements Serializable {
-    private static final long serialVersionUID = 1L;
-
-    private final ObjectId prior;
-    private final ObjectId next;
-    private final String strategyName;
-    private transient Repository repo;
-
-    private Key(ObjectId prior, ObjectId next, String strategyName,
-        Repository repo) {
-      this.prior = prior.copy();
-      this.next = next.copy();
-      this.strategyName = strategyName;
-      this.repo = repo;
-    }
-
-    public ObjectId getPrior() {
-      return prior;
-    }
-
-    public ObjectId getNext() {
-      return next;
-    }
-
-    public String getStrategyName() {
-      return strategyName;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      if (o instanceof Key) {
-        Key k = (Key) o;
-        return Objects.equal(prior, k.prior)
-            && Objects.equal(next, k.next)
-            && Objects.equal(strategyName, k.strategyName);
-      }
-      return false;
-    }
-
-    @Override
-    public int hashCode() {
-      return Objects.hashCode(prior, next, strategyName);
-    }
-  }
-
-  @Singleton
-  private static class Loader extends CacheLoader<Key, ChangeKind> {
-    @Override
-    public ChangeKind load(Key key) throws IOException {
-      RevWalk walk = new RevWalk(key.repo);
-      try {
-        RevCommit prior = walk.parseCommit(key.prior);
-        walk.parseBody(prior);
-        RevCommit next = walk.parseCommit(key.next);
-        walk.parseBody(next);
-
-        if (!next.getFullMessage().equals(prior.getFullMessage())) {
-          if (next.getTree() == prior.getTree() && isSameParents(prior, next)) {
-            return ChangeKind.NO_CODE_CHANGE;
-          } else {
-            return ChangeKind.REWORK;
-          }
-        }
-
-        if (prior.getParentCount() != 1 || next.getParentCount() != 1) {
-          // Trivial rebases done by machine only work well on 1 parent.
-          return ChangeKind.REWORK;
-        }
-
-        if (next.getTree() == prior.getTree() &&
-           isSameParents(prior, next)) {
-          return ChangeKind.TRIVIAL_REBASE;
-        }
-
-        // A trivial rebase can be detected by looking for the next commit
-        // having the same tree as would exist when the prior commit is
-        // cherry-picked onto the next commit's new first parent.
-        ThreeWayMerger merger = MergeUtil.newThreeWayMerger(
-            key.repo, MergeUtil.createDryRunInserter(), key.strategyName);
-        merger.setBase(prior.getParent(0));
-        if (merger.merge(next.getParent(0), prior)
-            && merger.getResultTreeId().equals(next.getTree())) {
-          return ChangeKind.TRIVIAL_REBASE;
-        } else {
-          return ChangeKind.REWORK;
-        }
-      } finally {
-        key.repo = null;
-        walk.release();
-      }
-    }
-
-    private static boolean isSameParents(RevCommit prior, RevCommit next) {
-      if (prior.getParentCount() != next.getParentCount()) {
-        return false;
-      } else if (prior.getParentCount() == 0) {
-        return true;
-      }
-      return prior.getParent(0).equals(next.getParent(0));
-    }
-  }
-
-  private final LoadingCache<Key, ChangeKind> cache;
-  private final boolean useRecursiveMerge;
-
-  @Inject
-  ChangeKindCache(
-      @GerritServerConfig Config serverConfig,
-      @Named(ID_CACHE) LoadingCache<Key, ChangeKind> cache) {
-    this.cache = cache;
-    this.useRecursiveMerge = MergeUtil.useRecursiveMerge(serverConfig);
-  }
-
+public interface ChangeKindCache {
   public ChangeKind getChangeKind(ProjectState project, Repository repo,
-      ObjectId prior, ObjectId next) {
-    checkNotNull(next, "next");
-    String strategyName = MergeUtil.mergeStrategyName(
-        project.isUseContentMerge(), useRecursiveMerge);
-    try {
-      return cache.get(new Key(prior, next, strategyName, repo));
-    } catch (ExecutionException e) {
-      log.warn("Cannot check trivial rebase of new patch set " + next.name()
-          + " in " + project.getProject().getName(), e);
-      return ChangeKind.REWORK;
-    }
-  }
+      ObjectId prior, ObjectId next);
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeKindCacheImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeKindCacheImpl.java
new file mode 100644
index 0000000..220dcb6
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeKindCacheImpl.java
@@ -0,0 +1,247 @@
+// 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.change;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.eclipse.jgit.lib.ObjectIdSerialization.readNotNull;
+import static org.eclipse.jgit.lib.ObjectIdSerialization.writeNotNull;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Objects;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.cache.Weigher;
+import com.google.gerrit.server.cache.CacheModule;
+import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.git.MergeUtil;
+import com.google.gerrit.server.project.ProjectState;
+import com.google.inject.Inject;
+import com.google.inject.Module;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
+
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.merge.ThreeWayMerger;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.concurrent.ExecutionException;
+
+public class ChangeKindCacheImpl implements ChangeKindCache {
+  private static final Logger log =
+      LoggerFactory.getLogger(ChangeKindCacheImpl.class);
+
+  private static final String ID_CACHE = "change_kind";
+
+  public static Module module() {
+    return new CacheModule() {
+      @Override
+      protected void configure() {
+        bind(ChangeKindCache.class).to(ChangeKindCacheImpl.class);
+        persist(ID_CACHE, Key.class, ChangeKind.class)
+            .maximumWeight(2 << 20)
+            .weigher(ChangeKindWeigher.class)
+            .loader(Loader.class);
+      }
+    };
+  }
+
+  @VisibleForTesting
+  public static class NoCache implements ChangeKindCache {
+    private final boolean useRecursiveMerge;
+
+    @Inject
+    NoCache(
+        @GerritServerConfig Config serverConfig) {
+      this.useRecursiveMerge = MergeUtil.useRecursiveMerge(serverConfig);
+    }
+
+    @Override
+    public ChangeKind getChangeKind(ProjectState project, Repository repo,
+        ObjectId prior, ObjectId next) {
+      try {
+        return new Loader().load(
+            new Key(project, repo, prior, next, useRecursiveMerge));
+      } catch (IOException e) {
+        log.warn("Cannot check trivial rebase of new patch set " + next.name()
+            + " in " + project.getProject().getName(), e);
+        return ChangeKind.REWORK;
+      }
+    }
+  }
+
+  public static class Key implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private transient ObjectId prior;
+    private transient ObjectId next;
+    private transient String strategyName;
+
+    private transient Repository repo; // Passed through to loader on miss.
+
+    private Key(ProjectState project, Repository repo, ObjectId prior,
+        ObjectId next, boolean useRecursiveMerge) {
+      checkNotNull(next, "next");
+      String strategyName = MergeUtil.mergeStrategyName(
+          project.isUseContentMerge(), useRecursiveMerge);
+      this.prior = prior.copy();
+      this.next = next.copy();
+      this.strategyName = strategyName;
+      this.repo = repo;
+    }
+
+    public Key(ObjectId prior, ObjectId next, String strategyName) {
+      this.prior = prior;
+      this.next = next;
+      this.strategyName = strategyName;
+    }
+
+    public ObjectId getPrior() {
+      return prior;
+    }
+
+    public ObjectId getNext() {
+      return next;
+    }
+
+    public String getStrategyName() {
+      return strategyName;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (o instanceof Key) {
+        Key k = (Key) o;
+        return Objects.equal(prior, k.prior)
+            && Objects.equal(next, k.next)
+            && Objects.equal(strategyName, k.strategyName);
+      }
+      return false;
+    }
+
+    @Override
+    public int hashCode() {
+      return Objects.hashCode(prior, next, strategyName);
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+      writeNotNull(out, prior);
+      writeNotNull(out, next);
+      out.writeUTF(strategyName);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException {
+      prior = readNotNull(in);
+      next = readNotNull(in);
+      strategyName = in.readUTF();
+    }
+  }
+
+  @Singleton
+  private static class Loader extends CacheLoader<Key, ChangeKind> {
+    @Override
+    public ChangeKind load(Key key) throws IOException {
+      RevWalk walk = new RevWalk(key.repo);
+      try {
+        RevCommit prior = walk.parseCommit(key.prior);
+        walk.parseBody(prior);
+        RevCommit next = walk.parseCommit(key.next);
+        walk.parseBody(next);
+
+        if (!next.getFullMessage().equals(prior.getFullMessage())) {
+          if (next.getTree() == prior.getTree() && isSameParents(prior, next)) {
+            return ChangeKind.NO_CODE_CHANGE;
+          } else {
+            return ChangeKind.REWORK;
+          }
+        }
+
+        if (prior.getParentCount() != 1 || next.getParentCount() != 1) {
+          // Trivial rebases done by machine only work well on 1 parent.
+          return ChangeKind.REWORK;
+        }
+
+        if (next.getTree() == prior.getTree() &&
+           isSameParents(prior, next)) {
+          return ChangeKind.TRIVIAL_REBASE;
+        }
+
+        // A trivial rebase can be detected by looking for the next commit
+        // having the same tree as would exist when the prior commit is
+        // cherry-picked onto the next commit's new first parent.
+        ThreeWayMerger merger = MergeUtil.newThreeWayMerger(
+            key.repo, MergeUtil.createDryRunInserter(), key.strategyName);
+        merger.setBase(prior.getParent(0));
+        if (merger.merge(next.getParent(0), prior)
+            && merger.getResultTreeId().equals(next.getTree())) {
+          return ChangeKind.TRIVIAL_REBASE;
+        } else {
+          return ChangeKind.REWORK;
+        }
+      } finally {
+        key.repo = null;
+        walk.release();
+      }
+    }
+
+    private static boolean isSameParents(RevCommit prior, RevCommit next) {
+      if (prior.getParentCount() != next.getParentCount()) {
+        return false;
+      } else if (prior.getParentCount() == 0) {
+        return true;
+      }
+      return prior.getParent(0).equals(next.getParent(0));
+    }
+  }
+
+  public static class ChangeKindWeigher implements Weigher<Key, ChangeKind> {
+    @Override
+    public int weigh(Key key, ChangeKind changeKind) {
+      return 16 + 2*36 + 2*key.strategyName.length() // Size of Key, 64 bit JVM
+          + 2*changeKind.name().length(); // Size of ChangeKind, 64 bit JVM
+    }
+  }
+
+  private final LoadingCache<Key, ChangeKind> cache;
+  private final boolean useRecursiveMerge;
+
+  @Inject
+  ChangeKindCacheImpl(
+      @GerritServerConfig Config serverConfig,
+      @Named(ID_CACHE) LoadingCache<Key, ChangeKind> cache) {
+    this.cache = cache;
+    this.useRecursiveMerge = MergeUtil.useRecursiveMerge(serverConfig);
+  }
+
+  @Override
+  public ChangeKind getChangeKind(ProjectState project, Repository repo,
+      ObjectId prior, ObjectId next) {
+    try {
+      return cache.get(new Key(project, repo, prior, next, useRecursiveMerge));
+    } catch (ExecutionException e) {
+      log.warn("Cannot check trivial rebase of new patch set " + next.name()
+          + " in " + project.getProject().getName(), e);
+      return ChangeKind.REWORK;
+    }
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/EditMessage.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/EditMessage.java
index 3477d45..b1a3290 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/EditMessage.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/EditMessage.java
@@ -65,6 +65,11 @@
       ResourceNotFoundException, EmailException, OrmException, IOException {
     if (Strings.isNullOrEmpty(input.message)) {
       throw new BadRequestException("message must be non-empty");
+    } else if (!rsrc.getPatchSet().getId()
+        .equals(rsrc.getChange().currentPatchSetId())) {
+      throw new ResourceConflictException(String.format(
+          "revision %s is not current revision",
+          rsrc.getPatchSet().getRevision().get()));
     }
     try {
       return json.format(changeUtil.editCommitMessage(
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDiff.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDiff.java
index 7267f7d..b3e77ef 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDiff.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDiff.java
@@ -33,9 +33,11 @@
 import com.google.gerrit.reviewdb.client.AccountDiffPreference;
 import com.google.gerrit.reviewdb.client.Patch.ChangeType;
 import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.server.git.LargeObjectException;
 import com.google.gerrit.server.patch.PatchScriptFactory;
 import com.google.gerrit.server.project.NoSuchChangeException;
-import com.google.gerrit.server.git.LargeObjectException;
+import com.google.gerrit.server.project.ProjectCache;
+import com.google.gerrit.server.project.ProjectState;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -55,6 +57,7 @@
 import java.util.concurrent.TimeUnit;
 
 public class GetDiff implements RestReadView<FileResource> {
+  private final ProjectCache projectCache;
   private final PatchScriptFactory.Factory patchScriptFactoryFactory;
   private final Provider<Revisions> revisions;
 
@@ -71,8 +74,10 @@
   boolean intraline;
 
   @Inject
-  GetDiff(PatchScriptFactory.Factory patchScriptFactoryFactory,
+  GetDiff(ProjectCache projectCache,
+      PatchScriptFactory.Factory patchScriptFactoryFactory,
       Provider<Revisions> revisions) {
+    this.projectCache = projectCache;
     this.patchScriptFactoryFactory = patchScriptFactoryFactory;
     this.revisions = revisions;
   }
@@ -92,14 +97,15 @@
     prefs.setIntralineDifference(intraline);
 
     try {
-      PatchScript ps = patchScriptFactoryFactory.create(
+      PatchScriptFactory psf = patchScriptFactoryFactory.create(
           resource.getRevision().getControl(),
           resource.getPatchKey().getFileName(),
           basePatchSet,
           resource.getPatchKey().getParentKey(),
-          prefs)
-            .call();
-
+          prefs);
+      psf.setLoadHistory(false);
+      psf.setLoadComments(context != AccountDiffPreference.WHOLE_FILE_CONTEXT);
+      PatchScript ps = psf.call();
       Content content = new Content(ps);
       for (Edit edit : ps.getEdits()) {
         if (edit.getType() == Edit.Type.EMPTY) {
@@ -127,18 +133,21 @@
       }
       content.addCommon(ps.getA().size());
 
+      ProjectState state =
+          projectCache.get(resource.getRevision().getChange().getProject());
+
       Result result = new Result();
       if (ps.getDisplayMethodA() != DisplayMethod.NONE) {
         result.metaA = new FileMeta();
         result.metaA.name = Objects.firstNonNull(ps.getOldName(), ps.getNewName());
-        result.metaA.setContentType(ps.getFileModeA(), ps.getMimeTypeA());
+        setContentType(result.metaA, state, ps.getFileModeA(), ps.getMimeTypeA());
         result.metaA.lines = ps.getA().size();
       }
 
       if (ps.getDisplayMethodB() != DisplayMethod.NONE) {
         result.metaB = new FileMeta();
         result.metaB.name = ps.getNewName();
-        result.metaB.setContentType(ps.getFileModeB(), ps.getMimeTypeB());
+        setContentType(result.metaB, state, ps.getFileModeB(), ps.getMimeTypeB());
         result.metaB.lines = ps.getB().size();
       }
 
@@ -182,21 +191,31 @@
     String name;
     String contentType;
     Integer lines;
+  }
 
-    void setContentType(FileMode fileMode, String mimeType) {
-      switch (fileMode) {
-        case FILE:
-          contentType = mimeType;
-          break;
-        case GITLINK:
-          contentType = "x-git/gitlink";
-          break;
-        case SYMLINK:
-          contentType = "x-git/symlink";
-          break;
-        default:
-          throw new IllegalStateException("file mode: " + fileMode);
-      }
+  private void setContentType(FileMeta meta, ProjectState project,
+      FileMode fileMode, String mimeType) {
+    switch (fileMode) {
+      case FILE:
+        if (project != null) {
+          for (ProjectState p : project.tree()) {
+            String t = p.getConfig().getMimeTypes().getMimeType(meta.name);
+            if (t != null) {
+              mimeType = t;
+              break;
+            }
+          }
+        }
+        meta.contentType = mimeType;
+        break;
+      case GITLINK:
+        meta.contentType = "x-git/gitlink";
+        break;
+      case SYMLINK:
+        meta.contentType = "x-git/symlink";
+        break;
+      default:
+        throw new IllegalStateException("file mode: " + fileMode);
     }
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java
index 25c63b5..0a2ccef 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java
@@ -469,7 +469,7 @@
     Map<String, PatchSetApproval> current = Maps.newHashMap();
 
     for (PatchSetApproval a : approvalsUtil.byPatchSetUser(
-        db.get(), rsrc.getNotes(), rsrc.getPatchSet().getId(),
+        db.get(), rsrc.getControl(), rsrc.getPatchSet().getId(),
         rsrc.getAccountId())) {
       if (a.isSubmit()) {
         continue;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReviewers.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReviewers.java
index 7fde39c..7f6fc97 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReviewers.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReviewers.java
@@ -239,6 +239,7 @@
         indexer.indexAsync(rsrc.getChange().getId());
     result.reviewers = Lists.newArrayListWithCapacity(added.size());
     for (PatchSetApproval psa : added) {
+      // New reviewers have value 0, don't bother normalizing.
       result.reviewers.add(json.format(
           new ReviewerInfo(psa.getAccountId()),
           reviewers.get(psa.getAccountId()),
@@ -272,7 +273,7 @@
         toMail.add(psa.getAccountId());
       }
     }
-    if (!added.isEmpty()) {
+    if (!toMail.isEmpty()) {
       try {
         AddReviewerSender cm = addReviewerSenderFactory.create(change);
         cm.setFrom(currentUser.getAccountId());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerJson.java
index 5008d02..2b9ca6a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerJson.java
@@ -29,7 +29,6 @@
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.ApprovalsUtil;
 import com.google.gerrit.server.account.AccountInfo;
-import com.google.gerrit.server.git.LabelNormalizer;
 import com.google.gerrit.server.notedb.ChangeNotes;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.query.change.ChangeData;
@@ -46,19 +45,16 @@
   private final Provider<ReviewDb> db;
   private final ChangeData.Factory changeDataFactory;
   private final ApprovalsUtil approvalsUtil;
-  private final LabelNormalizer labelNormalizer;
   private final AccountInfo.Loader.Factory accountLoaderFactory;
 
   @Inject
   ReviewerJson(Provider<ReviewDb> db,
       ChangeData.Factory changeDataFactory,
       ApprovalsUtil approvalsUtil,
-      LabelNormalizer labelNormalizer,
       AccountInfo.Loader.Factory accountLoaderFactory) {
     this.db = db;
     this.changeDataFactory = changeDataFactory;
     this.approvalsUtil = approvalsUtil;
-    this.labelNormalizer = labelNormalizer;
     this.accountLoaderFactory = accountLoaderFactory;
   }
 
@@ -86,17 +82,16 @@
       ChangeNotes changeNotes) throws OrmException {
     PatchSet.Id psId = ctl.getChange().currentPatchSetId();
     return format(out, ctl,
-        approvalsUtil.byPatchSetUser(db.get(), changeNotes, psId, out._id));
+        approvalsUtil.byPatchSetUser(db.get(), ctl, psId, out._id));
   }
 
   public ReviewerInfo format(ReviewerInfo out, ChangeControl ctl,
-      List<PatchSetApproval> approvals) throws OrmException {
+      Iterable<PatchSetApproval> approvals) throws OrmException {
     LabelTypes labelTypes = ctl.getLabelTypes();
 
     // Don't use Maps.newTreeMap(Comparator) due to OpenJDK bug 100167.
-    out.approvals = new TreeMap<String,String>(labelTypes.nameComparator());
-    for (PatchSetApproval ca :
-        labelNormalizer.normalize(ctl, approvals).getNormalized()) {
+    out.approvals = new TreeMap<>(labelTypes.nameComparator());
+    for (PatchSetApproval ca : approvals) {
       for (PermissionRange pr : ctl.getLabelRanges()) {
         if (!pr.isEmpty()) {
           LabelType at = labelTypes.byLabel(ca.getLabelId());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java
index f585f16..2121e7b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java
@@ -188,7 +188,8 @@
           "Merge patch set %d into %s",
           resource.getPatchSet().getPatchSetId(),
           resource.getChange().getDest().getShortName()))
-      .setVisible(resource.getChange().getStatus().isOpen()
+      .setVisible(!resource.getPatchSet().isDraft()
+          && resource.getChange().getStatus().isOpen()
           && resource.getPatchSet().getId().equals(current)
           && resource.getControl().canSubmit());
   }
@@ -257,12 +258,9 @@
       ChangeUpdate update, IdentifiedUser caller, Timestamp timestamp)
       throws OrmException {
     PatchSet.Id psId = rsrc.getPatchSet().getId();
-    List<PatchSetApproval> approvals =
-        approvalsUtil.byPatchSet(dbProvider.get(), rsrc.getNotes(), psId);
-
-    Map<PatchSetApproval.Key, PatchSetApproval> byKey =
-        Maps.newHashMapWithExpectedSize(approvals.size());
-    for (PatchSetApproval psa : approvals) {
+    Map<PatchSetApproval.Key, PatchSetApproval> byKey = Maps.newHashMap();
+    for (PatchSetApproval psa :
+        approvalsUtil.byPatchSet(dbProvider.get(), rsrc.getControl(), psId)) {
       if (!byKey.containsKey(psa.getKey())) {
         byKey.put(psa.getKey(), psa);
       }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfig.java
index a633acd..1d640c2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfig.java
@@ -112,7 +112,7 @@
       s = new String[] {"http://", "https://"};
     }
 
-    List<OpenIdProviderPattern> r = new ArrayList<OpenIdProviderPattern>();
+    List<OpenIdProviderPattern> r = new ArrayList<>();
     for (String pattern : s) {
       r.add(OpenIdProviderPattern.create(pattern));
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigUtil.java
index e081b02..ab290cb 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigUtil.java
@@ -165,7 +165,7 @@
   public static <T extends Enum<?>> List<T> getEnumList(final Config config,
       final String section, final String subsection, final String setting,
       final T[] all, final T defaultValue) {
-    final List<T> list = new ArrayList<T>();
+    final List<T> list = new ArrayList<>();
     final String[] values = config.getStringList(section, subsection, setting);
     if (values.length == 0) {
       list.add(defaultValue);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/DownloadConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/DownloadConfig.java
index f259871..80031c2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/DownloadConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/DownloadConfig.java
@@ -40,13 +40,13 @@
         ConfigUtil.getEnumList(cfg, "download", null, "scheme",
             DownloadScheme.DEFAULT_DOWNLOADS);
     downloadSchemes =
-        Collections.unmodifiableSet(new HashSet<DownloadScheme>(allSchemes));
+        Collections.unmodifiableSet(new HashSet<>(allSchemes));
 
     List<DownloadCommand> allCommands =
         ConfigUtil.getEnumList(cfg, "download", null, "command",
             DownloadCommand.DEFAULT_DOWNLOADS);
     downloadCommands =
-        Collections.unmodifiableSet(new HashSet<DownloadCommand>(allCommands));
+        Collections.unmodifiableSet(new HashSet<>(allCommands));
   }
 
   /** Scheme used to download. */
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
index a1c2ddb..023c115 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
@@ -69,7 +69,7 @@
 import com.google.gerrit.server.auth.UniversalAuthBackend;
 import com.google.gerrit.server.avatar.AvatarProvider;
 import com.google.gerrit.server.cache.CacheRemovalListener;
-import com.google.gerrit.server.change.ChangeKindCache;
+import com.google.gerrit.server.change.ChangeKindCacheImpl;
 import com.google.gerrit.server.change.MergeabilityChecker;
 import com.google.gerrit.server.events.EventFactory;
 import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
@@ -156,7 +156,7 @@
     install(AccountByEmailCacheImpl.module());
     install(AccountCacheImpl.module());
     install(ChangeCache.module());
-    install(ChangeKindCache.module());
+    install(ChangeKindCacheImpl.module());
     install(ConflictsCacheImpl.module());
     install(GroupCacheImpl.module());
     install(GroupIncludeCacheImpl.module());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GetPreferences.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GetPreferences.java
index 8cd7c19..f6c1d1d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GetPreferences.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GetPreferences.java
@@ -15,22 +15,38 @@
 package com.google.gerrit.server.config;
 
 import com.google.gerrit.extensions.restapi.RestReadView;
-import com.google.gerrit.reviewdb.client.RefNames;
 import com.google.gerrit.server.account.GetPreferences.PreferenceInfo;
-import com.google.gerrit.server.project.ProjectCache;
-import com.google.gerrit.server.project.ProjectState;
+import com.google.gerrit.server.account.VersionedAccountPreferences;
+import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.inject.Inject;
 
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.Repository;
+
+import java.io.IOException;
+
 public class GetPreferences implements RestReadView<ConfigResource> {
-  private final ProjectState allUsers;
+  private final AllUsersName allUsersName;
+  private final GitRepositoryManager gitMgr;
 
   @Inject
-  public GetPreferences(ProjectCache projectCache) {
-    this.allUsers = projectCache.getAllUsers();
+  public GetPreferences(AllUsersName allUsersName,
+      GitRepositoryManager gitMgr) {
+    this.allUsersName = allUsersName;
+    this.gitMgr = gitMgr;
   }
 
   @Override
-  public PreferenceInfo apply(ConfigResource rsrc) {
-    return new PreferenceInfo(null, RefNames.REFS_USER + "default", allUsers);
+  public PreferenceInfo apply(ConfigResource rsrc)
+      throws IOException, ConfigInvalidException {
+    Repository git = gitMgr.openRepository(allUsersName);
+    try {
+      VersionedAccountPreferences p =
+          VersionedAccountPreferences.forDefault();
+      p.load(git);
+      return new PreferenceInfo(null, p, git);
+    } finally {
+      git.close();
+    }
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/SetPreferences.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/SetPreferences.java
index f93e908..e6f5253 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/SetPreferences.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/SetPreferences.java
@@ -18,29 +18,31 @@
 import com.google.gerrit.extensions.annotations.RequiresCapability;
 import com.google.gerrit.extensions.restapi.BadRequestException;
 import com.google.gerrit.extensions.restapi.RestModifyView;
-import com.google.gerrit.reviewdb.client.RefNames;
+import com.google.gerrit.server.account.GetPreferences.PreferenceInfo;
 import com.google.gerrit.server.account.SetPreferences.Input;
+import com.google.gerrit.server.account.VersionedAccountPreferences;
+import com.google.gerrit.server.git.MetaDataUpdate;
 import com.google.inject.Inject;
-import com.google.inject.Provider;
+
+import org.eclipse.jgit.errors.ConfigInvalidException;
 
 import java.io.IOException;
 
 @RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
 public class SetPreferences implements RestModifyView<ConfigResource, Input> {
-  private final Provider<com.google.gerrit.server.account.SetPreferences> setPreferences;
-  private final Provider<GetPreferences> getDefaultPreferences;
+  private final MetaDataUpdate.User metaDataUpdateFactory;
+  private final AllUsersName allUsersName;
 
   @Inject
-  SetPreferences(
-      Provider<com.google.gerrit.server.account.SetPreferences> setPreferences,
-      Provider<GetPreferences> getDefaultPreferences) {
-    this.setPreferences = setPreferences;
-    this.getDefaultPreferences = getDefaultPreferences;
+  SetPreferences(MetaDataUpdate.User metaDataUpdateFactory,
+      AllUsersName allUsersName) {
+    this.metaDataUpdateFactory = metaDataUpdateFactory;
+    this.allUsersName = allUsersName;
   }
 
   @Override
   public Object apply(ConfigResource rsrc, Input i) throws BadRequestException,
-      IOException {
+      IOException, ConfigInvalidException {
     if (i.changesPerPage != null || i.showSiteHeader != null
         || i.useFlashClipboard != null || i.downloadScheme != null
         || i.downloadCommand != null || i.copySelfOnEmail != null
@@ -53,9 +55,17 @@
         || i.changeScreen != null) {
       throw new BadRequestException("unsupported option");
     }
-    if (i.my != null) {
-      setPreferences.get().storeMyMenus(RefNames.REFS_USER + "default", i.my);
+
+    VersionedAccountPreferences p;
+    MetaDataUpdate md = metaDataUpdateFactory.create(allUsersName);
+    try {
+      p = VersionedAccountPreferences.forDefault();
+      p.load(md);
+      com.google.gerrit.server.account.SetPreferences.storeMyMenus(p, i.my);
+      p.commit(md);
+      return new PreferenceInfo(null, p, md.getRepository());
+    } finally {
+      md.close();
     }
-    return getDefaultPreferences.get().apply(rsrc);
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/TrackingFootersProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/TrackingFootersProvider.java
index c10c0eb..a76b010 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/TrackingFootersProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/TrackingFootersProvider.java
@@ -34,8 +34,7 @@
   private static String FOOTER_TAG = "footer";
   private static String SYSTEM_TAG = "system";
   private static String REGEX_TAG = "match";
-  private final List<TrackingFooter> trackingFooters =
-      new ArrayList<TrackingFooter>();
+  private final List<TrackingFooter> trackingFooters = new ArrayList<>();
   private static final Logger log =
       LoggerFactory.getLogger(TrackingFootersProvider.class);
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/events/EventFactory.java b/gerrit-server/src/main/java/com/google/gerrit/server/events/EventFactory.java
index 9d48574..3045a86 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/events/EventFactory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/events/EventFactory.java
@@ -190,7 +190,7 @@
    */
   public void addSubmitRecords(ChangeAttribute ca,
       List<SubmitRecord> submitRecords) {
-    ca.submitRecords = new ArrayList<SubmitRecordAttribute>();
+    ca.submitRecords = new ArrayList<>();
 
     for (SubmitRecord submitRecord : submitRecords) {
       SubmitRecordAttribute sa = new SubmitRecordAttribute();
@@ -209,7 +209,7 @@
   private void addSubmitRecordLabels(SubmitRecord submitRecord,
       SubmitRecordAttribute sa) {
     if (submitRecord.labels != null && !submitRecord.labels.isEmpty()) {
-      sa.labels = new ArrayList<SubmitLabelAttribute>();
+      sa.labels = new ArrayList<>();
       for (SubmitRecord.Label lbl : submitRecord.labels) {
         SubmitLabelAttribute la = new SubmitLabelAttribute();
         la.label = lbl.label;
@@ -224,8 +224,8 @@
   }
 
   public void addDependencies(ChangeAttribute ca, Change change) {
-    ca.dependsOn = new ArrayList<DependencyAttribute>();
-    ca.neededBy = new ArrayList<DependencyAttribute>();
+    ca.dependsOn = new ArrayList<>();
+    ca.neededBy = new ArrayList<>();
     try {
       final ReviewDb db = schema.open();
       try {
@@ -293,7 +293,7 @@
 
   public void addTrackingIds(ChangeAttribute a, Multimap<String, String> set) {
     if (!set.isEmpty()) {
-      a.trackingIds = new ArrayList<TrackingIdAttribute>(set.size());
+      a.trackingIds = new ArrayList<>(set.size());
       for (Map.Entry<String, Collection<String>> e : set.asMap().entrySet()) {
         for (String id : e.getValue()) {
           TrackingIdAttribute t = new TrackingIdAttribute();
@@ -324,7 +324,7 @@
       Map<PatchSet.Id, Collection<PatchSetApproval>> approvals,
       boolean includeFiles, Change change, LabelTypes labelTypes) {
     if (!ps.isEmpty()) {
-      ca.patchSets = new ArrayList<PatchSetAttribute>(ps.size());
+      ca.patchSets = new ArrayList<>(ps.size());
       for (PatchSet p : ps) {
         PatchSetAttribute psa = asPatchSetAttribute(p);
         if (approvals != null) {
@@ -344,8 +344,7 @@
       if (comment.getKey().getParentKey().getParentKey().get()
           == Integer.parseInt(patchSetAttribute.number)) {
         if (patchSetAttribute.comments == null) {
-          patchSetAttribute.comments =
-            new ArrayList<PatchSetCommentAttribute>();
+          patchSetAttribute.comments = new ArrayList<>();
         }
         patchSetAttribute.comments.add(asPatchSetLineAttribute(comment));
       }
@@ -358,7 +357,7 @@
       PatchList patchList = patchListCache.get(change, patchSet);
       for (PatchListEntry patch : patchList.getPatches()) {
         if (patchSetAttribute.files == null) {
-          patchSetAttribute.files = new ArrayList<PatchAttribute>();
+          patchSetAttribute.files = new ArrayList<>();
         }
 
         PatchAttribute p = new PatchAttribute();
@@ -376,7 +375,7 @@
   public void addComments(ChangeAttribute ca,
       Collection<ChangeMessage> messages) {
     if (!messages.isEmpty()) {
-      ca.comments = new ArrayList<MessageAttribute>();
+      ca.comments = new ArrayList<>();
       for (ChangeMessage message : messages) {
         ca.comments.add(asMessageAttribute(message));
       }
@@ -402,7 +401,7 @@
     try {
       final ReviewDb db = schema.open();
       try {
-        p.parents = new ArrayList<String>();
+        p.parents = new ArrayList<>();
         for (PatchSetAncestor a : db.patchSetAncestors().ancestorsOf(
             patchSet.getId())) {
           p.parents.add(a.getAncestorRevision().get());
@@ -452,7 +451,7 @@
   public void addApprovals(PatchSetAttribute p,
       Collection<PatchSetApproval> list, LabelTypes labelTypes) {
     if (!list.isEmpty()) {
-      p.approvals = new ArrayList<ApprovalAttribute>(list.size());
+      p.approvals = new ArrayList<>(list.size());
       for (PatchSetApproval a : list) {
         if (a.getValue() != 0) {
           p.approvals.add(asApprovalAttribute(a, labelTypes));
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/AccountsSection.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/AccountsSection.java
index 7d868bf..4ea24ef 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/AccountsSection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/AccountsSection.java
@@ -24,7 +24,7 @@
 
   public List<PermissionRule> getSameGroupVisibility() {
     if (sameGroupVisibility == null) {
-      sameGroupVisibility = new ArrayList<PermissionRule>();
+      sameGroupVisibility = new ArrayList<>();
     }
     return sameGroupVisibility;
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/BanCommitResult.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/BanCommitResult.java
index 1b48455..baae629 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/BanCommitResult.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/BanCommitResult.java
@@ -21,9 +21,9 @@
 
 public class BanCommitResult {
 
-  private final List<ObjectId> newlyBannedCommits = new LinkedList<ObjectId>();
-  private final List<ObjectId> alreadyBannedCommits = new LinkedList<ObjectId>();
-  private final List<ObjectId> ignoredObjectIds = new LinkedList<ObjectId>();
+  private final List<ObjectId> newlyBannedCommits = new LinkedList<>();
+  private final List<ObjectId> alreadyBannedCommits = new LinkedList<>();
+  private final List<ObjectId> ignoredObjectIds = new LinkedList<>();
 
   public BanCommitResult() {
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ChangeMergeQueue.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ChangeMergeQueue.java
index a6b0a12..a1dc71b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ChangeMergeQueue.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ChangeMergeQueue.java
@@ -55,10 +55,8 @@
   private static final Logger log =
       LoggerFactory.getLogger(ChangeMergeQueue.class);
 
-  private final Map<Branch.NameKey, MergeEntry> active =
-      new HashMap<Branch.NameKey, MergeEntry>();
-  private final Map<Branch.NameKey, RecheckJob> recheck =
-      new HashMap<Branch.NameKey, RecheckJob>();
+  private final Map<Branch.NameKey, MergeEntry> active = new HashMap<>();
+  private final Map<Branch.NameKey, RecheckJob> recheck = new HashMap<>();
 
   private final WorkQueue workQueue;
   private final Provider<MergeOp.Factory> bgFactory;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ConfiguredMimeTypes.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ConfiguredMimeTypes.java
new file mode 100644
index 0000000..082e1a2
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ConfiguredMimeTypes.java
@@ -0,0 +1,117 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.git;
+
+import org.eclipse.jgit.errors.InvalidPatternException;
+import org.eclipse.jgit.fnmatch.FileNameMatcher;
+import org.eclipse.jgit.lib.Config;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+public class ConfiguredMimeTypes {
+  private static final Logger log = LoggerFactory
+      .getLogger(ConfiguredMimeTypes.class);
+
+  private static final String MIMETYPE = "mimetype";
+  private static final String KEY_PATH = "path";
+
+  private final List<TypeMatcher> matchers;
+
+  ConfiguredMimeTypes(String projectName, Config rc) {
+    Set<String> types = rc.getSubsections(MIMETYPE);
+    if (types.isEmpty()) {
+      matchers = Collections.emptyList();
+    } else {
+      matchers = new ArrayList<>();
+      for (String typeName : types) {
+        for (String path : rc.getStringList(MIMETYPE, typeName, KEY_PATH)) {
+          try {
+            add(typeName, path);
+          } catch (PatternSyntaxException | InvalidPatternException e) {
+            log.warn(String.format(
+                "Ignoring invalid %s.%s.%s = %s in project %s: %s",
+                MIMETYPE, typeName, KEY_PATH,
+                path, projectName, e.getMessage()));
+          }
+        }
+      }
+    }
+  }
+
+  private void add(String typeName, String path)
+      throws PatternSyntaxException, InvalidPatternException {
+    if (path.startsWith("^")) {
+      matchers.add(new ReType(typeName, path));
+    } else {
+      matchers.add(new FnType(typeName, path));
+    }
+  }
+
+  public String getMimeType(String path) {
+    for (TypeMatcher m : matchers) {
+      if (m.matches(path)) {
+        return m.type;
+      }
+    }
+    return null;
+  }
+
+  private abstract static class TypeMatcher {
+    final String type;
+
+    TypeMatcher(String type) {
+      this.type = type;
+    }
+
+    abstract boolean matches(String path);
+  }
+
+  private static class FnType extends TypeMatcher {
+    private final FileNameMatcher matcher;
+
+    FnType(String type, String pattern) throws InvalidPatternException {
+      super(type);
+      this.matcher = new FileNameMatcher(pattern, null);
+    }
+
+    @Override
+    boolean matches(String input) {
+      FileNameMatcher m = new FileNameMatcher(matcher);
+      m.append(input);
+      return m.isMatch();
+    }
+  }
+
+  private static class ReType extends TypeMatcher {
+    private final Pattern re;
+
+    ReType(String type, String pattern) throws PatternSyntaxException {
+      super(type);
+      this.re = Pattern.compile(pattern);
+    }
+
+    @Override
+    boolean matches(String input) {
+      return re.matcher(input).matches();
+    }
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/InsertException.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/InsertException.java
new file mode 100644
index 0000000..575ad52
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/InsertException.java
@@ -0,0 +1,30 @@
+//Copyright (C) 2014 The Android Open Source Project
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+package com.google.gerrit.server.git;
+
+/**
+ * Thrown in inserting change or patchset, e.g. OrmException or IOException.
+ */
+public class InsertException extends Exception {
+  private static final long serialVersionUID = 1L;
+
+  InsertException(final String msg) {
+    super(msg, null);
+  }
+
+  InsertException(final String msg, final Throwable why) {
+    super(msg, why);
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
index 43e0156..196d3e9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
@@ -234,7 +234,7 @@
   private void onCreateProject(final Project.NameKey newProjectName) {
     namesUpdateLock.lock();
     try {
-      SortedSet<Project.NameKey> n = new TreeSet<Project.NameKey>(names);
+      SortedSet<Project.NameKey> n = new TreeSet<>(names);
       n.add(newProjectName);
       names = Collections.unmodifiableSortedSet(n);
     } finally {
@@ -345,7 +345,7 @@
     // scanning the filesystem. Don't rely on the cached names collection.
     namesUpdateLock.lock();
     try {
-      SortedSet<Project.NameKey> n = new TreeSet<Project.NameKey>();
+      SortedSet<Project.NameKey> n = new TreeSet<>();
       scanProjects(basePath, "", n);
       names = Collections.unmodifiableSortedSet(n);
       return n;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
index 78a2bc2..4324d1a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
@@ -206,8 +206,8 @@
     this.approvalsUtil = approvalsUtil;
     destBranch = branch;
     toMerge = ArrayListMultimap.create();
-    potentiallyStillSubmittable = new ArrayList<CodeReviewCommit>();
-    commits = new HashMap<Change.Id, CodeReviewCommit>();
+    potentiallyStillSubmittable = new ArrayList<>();
+    commits = new HashMap<>();
     toUpdate = Lists.newArrayList();
   }
 
@@ -238,11 +238,11 @@
       final ListMultimap<SubmitType, CodeReviewCommit> toMergeNextTurn =
           ArrayListMultimap.create();
       final List<CodeReviewCommit> potentiallyStillSubmittableOnNextRun =
-          new ArrayList<CodeReviewCommit>();
+          new ArrayList<>();
       while (!toMerge.isEmpty()) {
         toMergeNextTurn.clear();
         final Set<SubmitType> submitTypes =
-            new HashSet<SubmitType>(toMerge.keySet());
+            new HashSet<>(toMerge.keySet());
         for (final SubmitType submitType : submitTypes) {
           if (reopen) {
             branchUpdate = openBranch();
@@ -418,7 +418,7 @@
 
   private Set<RevCommit> getAlreadyAccepted(final CodeReviewCommit branchTip)
       throws MergeException {
-    final Set<RevCommit> alreadyAccepted = new HashSet<RevCommit>();
+    final Set<RevCommit> alreadyAccepted = new HashSet<>();
 
     if (branchTip != null) {
       alreadyAccepted.add(branchTip);
@@ -453,7 +453,7 @@
       throw new MergeException(e.getMessage(), e);
     }
 
-    final Set<ObjectId> tips = new HashSet<ObjectId>();
+    final Set<ObjectId> tips = new HashSet<>();
     for (final Ref r : allRefs.values()) {
       tips.add(r.getObjectId());
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeSorter.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeSorter.java
index 9b4582d..4985390 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeSorter.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeSorter.java
@@ -40,8 +40,8 @@
 
   Collection<CodeReviewCommit> sort(final Collection<CodeReviewCommit> incoming)
       throws IOException {
-    final Set<CodeReviewCommit> heads = new HashSet<CodeReviewCommit>();
-    final Set<CodeReviewCommit> sort = new HashSet<CodeReviewCommit>(incoming);
+    final Set<CodeReviewCommit> heads = new HashSet<>();
+    final Set<CodeReviewCommit> sort = new HashSet<>(incoming);
     while (!sort.isEmpty()) {
       final CodeReviewCommit n = removeOne(sort);
 
@@ -52,7 +52,7 @@
       }
 
       RevCommit c;
-      final RevCommitList<RevCommit> contents = new RevCommitList<RevCommit>();
+      final RevCommitList<RevCommit> contents = new RevCommitList<>();
       while ((c = rw.next()) != null) {
         if (!c.has(canMergeFlag) || !incoming.contains(c)) {
           // We cannot merge n as it would bring something we
@@ -60,7 +60,7 @@
           //
           if (n.missing == null) {
             n.setStatusCode(CommitMergeStatus.MISSING_DEPENDENCY);
-            n.missing = new ArrayList<CodeReviewCommit>();
+            n.missing = new ArrayList<>();
           }
           n.missing.add((CodeReviewCommit) c);
         } else {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeUtil.java
index b9624fe..742499b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeUtil.java
@@ -311,9 +311,9 @@
     return "Verified".equalsIgnoreCase(id.get());
   }
 
-  private List<PatchSetApproval> safeGetApprovals(CodeReviewCommit n) {
+  private Iterable<PatchSetApproval> safeGetApprovals(CodeReviewCommit n) {
     try {
-      return approvalsUtil.byPatchSet(db.get(), n.notes(), n.getPatchsetId());
+      return approvalsUtil.byPatchSet(db.get(), n.getControl(), n.getPatchsetId());
     } catch (OrmException e) {
       log.error("Can't read approval records for " + n.getPatchsetId(), e);
       return Collections.emptyList();
@@ -360,7 +360,7 @@
     if (submitter != null) {
       IdentifiedUser who =
           identifiedUserFactory.create(submitter.getAccountId());
-      Set<String> emails = new HashSet<String>();
+      Set<String> emails = new HashSet<>();
       for (RevCommit c : codeReviewCommits) {
         try {
           rw.parseBody(c);
@@ -551,7 +551,7 @@
       final CodeReviewCommit mergeTip, final ObjectId treeId,
       final CodeReviewCommit n) throws IOException,
       MissingObjectException, IncorrectObjectTypeException {
-    final List<CodeReviewCommit> merged = new ArrayList<CodeReviewCommit>();
+    final List<CodeReviewCommit> merged = new ArrayList<>();
     rw.resetRetain(canMergeFlag);
     rw.markStart(n);
     rw.markUninteresting(mergeTip);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MetaDataUpdate.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MetaDataUpdate.java
index e8b4b6a..b48028e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MetaDataUpdate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MetaDataUpdate.java
@@ -137,7 +137,7 @@
     return projectName;
   }
 
-  Repository getRepository() {
+  public Repository getRepository() {
     return db;
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MultiProgressMonitor.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MultiProgressMonitor.java
index 45ecb63..4279b31 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MultiProgressMonitor.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MultiProgressMonitor.java
@@ -132,7 +132,7 @@
 
   private final OutputStream out;
   private final String taskName;
-  private final List<Task> tasks = new CopyOnWriteArrayList<Task>();
+  private final List<Task> tasks = new CopyOnWriteArrayList<>();
   private int spinnerIndex;
   private char spinnerState = NO_SPINNER;
   private boolean done;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/PerThreadRequestScope.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/PerThreadRequestScope.java
index e7bb0ae..6087432 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/PerThreadRequestScope.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/PerThreadRequestScope.java
@@ -81,7 +81,7 @@
     }
   }
 
-  private static final ThreadLocal<Context> current = new ThreadLocal<Context>();
+  private static final ThreadLocal<Context> current = new ThreadLocal<>();
 
   private static Context requireContext() {
     final Context ctx = current.get();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
index 4971f84..d5dae8e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
@@ -43,9 +43,9 @@
 import com.google.gerrit.extensions.common.InheritableBoolean;
 import com.google.gerrit.extensions.common.SubmitType;
 import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.reviewdb.client.RefNames;
 import com.google.gerrit.reviewdb.client.AccountProjectWatch.NotifyType;
 import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.RefNames;
 import com.google.gerrit.server.account.GroupBackend;
 import com.google.gerrit.server.config.ConfigUtil;
 import com.google.gerrit.server.config.PluginConfig;
@@ -129,6 +129,7 @@
   private static final String LABEL = "label";
   private static final String KEY_ABBREVIATION = "abbreviation";
   private static final String KEY_FUNCTION = "function";
+  private static final String KEY_DEFAULT_VALUE = "defaultValue";
   private static final String KEY_COPY_MIN_SCORE = "copyMinScore";
   private static final String KEY_COPY_MAX_SCORE = "copyMaxScore";
   private static final String KEY_COPY_ALL_SCORES_ON_TRIVIAL_REBASE = "copyAllScoresOnTrivialRebase";
@@ -154,6 +155,7 @@
   private Map<String, ContributorAgreement> contributorAgreements;
   private Map<String, NotifyConfig> notifySections;
   private Map<String, LabelType> labelSections;
+  private ConfiguredMimeTypes mimeTypes;
   private List<CommentLinkInfo> commentLinkSections;
   private List<ValidationError> validationErrors;
   private ObjectId rulesId;
@@ -300,6 +302,10 @@
     return commentLinkSections;
   }
 
+  public ConfiguredMimeTypes getMimeTypes() {
+    return mimeTypes;
+  }
+
   public GroupReference resolve(AccountGroup group) {
     return resolve(GroupReference.forGroup(group));
   }
@@ -417,6 +423,7 @@
     loadNotifySections(rc, groupsByName);
     loadLabelSections(rc);
     loadCommentLinkSections(rc);
+    mimeTypes = new ConfiguredMimeTypes(projectName.get(), rc);
     loadPluginSections(rc);
     loadReceiveSection(rc);
   }
@@ -430,7 +437,7 @@
 
   private void loadContributorAgreements(
       Config rc, Map<String, GroupReference> groupsByName) {
-    contributorAgreements = new HashMap<String, ContributorAgreement>();
+    contributorAgreements = new HashMap<>();
     for (String name : rc.getSubsections(CONTRIBUTOR_AGREEMENT)) {
       ContributorAgreement ca = getContributorAgreement(name, true);
       ca.setDescription(rc.getString(CONTRIBUTOR_AGREEMENT, name, KEY_DESCRIPTION));
@@ -528,7 +535,7 @@
 
   private void loadAccessSections(
       Config rc, Map<String, GroupReference> groupsByName) {
-    accessSections = new HashMap<String, AccessSection>();
+    accessSections = new HashMap<>();
     for (String refName : rc.getSubsections(ACCESS)) {
       if (RefConfigSection.isValid(refName)) {
         AccessSection as = getAccessSection(refName, true);
@@ -665,6 +672,15 @@
             KEY_FUNCTION, name, Joiner.on(", ").join(LABEL_FUNCTIONS))));
         label.setFunctionName(null);
       }
+
+      short dv = (short) rc.getInt(LABEL, name, KEY_DEFAULT_VALUE, 0);
+      if (isInRange(dv, values)) {
+        label.setDefaultValue(dv);
+      } else {
+        error(new ValidationError(PROJECT_CONFIG, String.format(
+            "Invalid %s \"%s\" for label \"%s\"",
+            KEY_DEFAULT_VALUE, dv, name)));
+      }
       label.setCopyMinScore(
           rc.getBoolean(LABEL, name, KEY_COPY_MIN_SCORE, false));
       label.setCopyMaxScore(
@@ -680,6 +696,15 @@
     }
   }
 
+  private boolean isInRange(short value, List<LabelValue> labelValues) {
+    for (LabelValue lv : labelValues) {
+      if (lv.getValue() == value) {
+        return true;
+      }
+    }
+    return false;
+  }
+
   private List<String> getStringListOrNull(Config rc, String section,
       String subSection, String name) {
     String[] ac = rc.getStringList(section, subSection, name);
@@ -732,9 +757,8 @@
   }
 
   private Map<String, GroupReference> readGroupList() throws IOException {
-    groupsByUUID = new HashMap<AccountGroup.UUID, GroupReference>();
-    Map<String, GroupReference> groupsByName =
-        new HashMap<String, GroupReference>();
+    groupsByUUID = new HashMap<>();
+    Map<String, GroupReference> groupsByName = new HashMap<>();
 
     BufferedReader br = new BufferedReader(new StringReader(readUTF8(GROUP_LIST)));
     String s;
@@ -789,7 +813,7 @@
     set(rc, DASHBOARD, null, KEY_DEFAULT, p.getDefaultDashboard());
     set(rc, DASHBOARD, null, KEY_LOCAL_DEFAULT, p.getLocalDefaultDashboard());
 
-    Set<AccountGroup.UUID> keepGroups = new HashSet<AccountGroup.UUID>();
+    Set<AccountGroup.UUID> keepGroups = new HashSet<>();
     saveAccountsSection(rc, keepGroups);
     saveContributorAgreements(rc, keepGroups);
     saveAccessSections(rc, keepGroups);
@@ -906,7 +930,7 @@
 
   private List<String> ruleToStringList(
       List<PermissionRule> list, Set<AccountGroup.UUID> keepGroups) {
-    List<String> rules = new ArrayList<String>();
+    List<String> rules = new ArrayList<>();
     for (PermissionRule rule : sort(list)) {
       if (rule.getGroup().getUUID() != null) {
         keepGroups.add(rule.getGroup().getUUID());
@@ -920,12 +944,12 @@
       Config rc, Set<AccountGroup.UUID> keepGroups) {
     AccessSection capability = accessSections.get(AccessSection.GLOBAL_CAPABILITIES);
     if (capability != null) {
-      Set<String> have = new HashSet<String>();
+      Set<String> have = new HashSet<>();
       for (Permission permission : sort(capability.getPermissions())) {
         have.add(permission.getName().toLowerCase());
 
         boolean needRange = GlobalCapability.hasRange(permission.getName());
-        List<String> rules = new ArrayList<String>();
+        List<String> rules = new ArrayList<>();
         for (PermissionRule rule : sort(permission.getRules())) {
           GroupReference group = rule.getGroup();
           if (group.getUUID() != null) {
@@ -965,12 +989,12 @@
         rc.unset(ACCESS, refName, KEY_GROUP_PERMISSIONS);
       }
 
-      Set<String> have = new HashSet<String>();
+      Set<String> have = new HashSet<>();
       for (Permission permission : sort(as.getPermissions())) {
         have.add(permission.getName().toLowerCase());
 
         boolean needRange = Permission.hasRange(permission.getName());
-        List<String> rules = new ArrayList<String>();
+        List<String> rules = new ArrayList<>();
         for (PermissionRule rule : sort(permission.getRules())) {
           GroupReference group = rule.getGroup();
           if (group.getUUID() != null) {
@@ -1018,6 +1042,8 @@
       } else {
         rc.unset(LABEL, name, KEY_ABBREVIATION);
       }
+
+      rc.setInt(LABEL, name, KEY_DEFAULT_VALUE, label.getDefaultValue());
       if (label.isCopyMinScore()) {
         rc.setBoolean(LABEL, name, KEY_COPY_MIN_SCORE, true);
       } else {
@@ -1112,7 +1138,7 @@
 
   private void error(ValidationError error) {
     if (validationErrors == null) {
-      validationErrors = new ArrayList<ValidationError>(4);
+      validationErrors = new ArrayList<>(4);
     }
     validationErrors.add(error);
   }
@@ -1131,7 +1157,7 @@
   }
 
   private static <T extends Comparable<? super T>> List<T> sort(Collection<T> m) {
-    ArrayList<T> r = new ArrayList<T>(m);
+    ArrayList<T> r = new ArrayList<>(m);
     Collections.sort(r);
     return r;
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectLevelConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectLevelConfig.java
index b141a46..b4f41a0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectLevelConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectLevelConfig.java
@@ -29,23 +29,17 @@
 /** Configuration file in the projects refs/meta/config branch. */
 public class ProjectLevelConfig extends VersionedMetaData {
   private final String fileName;
-  private final String ref;
   private final ProjectState project;
   private Config cfg;
 
   public ProjectLevelConfig(String fileName, ProjectState project) {
-    this(fileName, RefNames.REFS_CONFIG, project);
-  }
-
-  public ProjectLevelConfig(String fileName, String ref, ProjectState project) {
     this.fileName = fileName;
     this.project = project;
-    this.ref = ref;
   }
 
   @Override
   protected String getRefName() {
-    return ref;
+    return RefNames.REFS_CONFIG;
   }
 
   @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/RebaseSorter.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/RebaseSorter.java
index b0232ca..8595582 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/RebaseSorter.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/RebaseSorter.java
@@ -42,8 +42,8 @@
 
   public List<CodeReviewCommit> sort(Collection<CodeReviewCommit> incoming)
       throws IOException {
-    final List<CodeReviewCommit> sorted = new ArrayList<CodeReviewCommit>();
-    final Set<CodeReviewCommit> sort = new HashSet<CodeReviewCommit>(incoming);
+    final List<CodeReviewCommit> sorted = new ArrayList<>();
+    final Set<CodeReviewCommit> sort = new HashSet<>(incoming);
     while (!sort.isEmpty()) {
       final CodeReviewCommit n = removeOne(sort);
 
@@ -54,7 +54,7 @@
       }
 
       CodeReviewCommit c;
-      final List<CodeReviewCommit> contents = new ArrayList<CodeReviewCommit>();
+      final List<CodeReviewCommit> contents = new ArrayList<>();
       while ((c = (CodeReviewCommit) rw.next()) != null) {
         if (!c.has(canMergeFlag) || !incoming.contains(c)) {
           // We cannot merge n as it would bring something we
@@ -62,7 +62,7 @@
           //
           if (n.missing == null) {
             n.setStatusCode(CommitMergeStatus.MISSING_DEPENDENCY);
-            n.missing = new ArrayList<CodeReviewCommit>();
+            n.missing = new ArrayList<>();
           }
           n.missing.add(c);
         } else {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
index b43967a..0256322 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
@@ -245,14 +245,17 @@
     }
   }
 
-  private static final Function<Exception, OrmException> ORM_EXCEPTION =
-      new Function<Exception, OrmException>() {
+  private static final Function<Exception, InsertException> INSERT_EXCEPTION =
+      new Function<Exception, InsertException>() {
         @Override
-        public OrmException apply(Exception input) {
+        public InsertException apply(Exception input) {
           if (input instanceof OrmException) {
-            return (OrmException) input;
+            return new InsertException("ORM error", input);
           }
-          return new OrmException("Error updating database", input);
+          if (input instanceof IOException) {
+            return new InsertException("IO error", input);
+          }
+          return new InsertException("Error inserting change/patchset", input);
         }
       };
 
@@ -301,10 +304,10 @@
 
   private List<CreateRequest> newChanges = Collections.emptyList();
   private final Map<Change.Id, ReplaceRequest> replaceByChange =
-      new HashMap<Change.Id, ReplaceRequest>();
+      new HashMap<>();
   private final Map<RevCommit, ReplaceRequest> replaceByCommit =
-      new HashMap<RevCommit, ReplaceRequest>();
-  private final Set<RevCommit> validCommits = new HashSet<RevCommit>();
+      new HashMap<>();
+  private final Set<RevCommit> validCommits = new HashSet<>();
 
   private ListMultimap<Change.Id, Ref> refsByChange;
   private SetMultimap<ObjectId, Ref> refsById;
@@ -315,7 +318,7 @@
   private final MergeQueue mergeQueue;
   private final DynamicMap<ProjectConfigEntry> pluginConfigEntries;
 
-  private final List<CommitValidationMessage> messages = new ArrayList<CommitValidationMessage>();
+  private final List<CommitValidationMessage> messages = new ArrayList<>();
   private ListMultimap<Error, String> errors = LinkedListMultimap.create();
   private Task newProgress;
   private Task replaceProgress;
@@ -434,7 +437,7 @@
       rp.setCheckReferencedObjectsAreReachable(config.checkReferencedObjectsAreReachable);
       rp.setAdvertiseRefsHook(new VisibleRefFilter(tagCache, changeCache, repo, projectControl, db, false));
     }
-    List<AdvertiseRefsHook> advHooks = new ArrayList<AdvertiseRefsHook>(3);
+    List<AdvertiseRefsHook> advHooks = new ArrayList<>(3);
     advHooks.add(new AdvertiseRefsHook() {
       @Override
       public void advertiseRefs(BaseReceivePack rp)
@@ -574,7 +577,7 @@
       if (c.getResult() == OK) {
         switch (c.getType()) {
           case CREATE:
-            if (isHead(c)) {
+            if (isHead(c) || isConfig(c)) {
               autoCloseChanges(c);
             }
             break;
@@ -584,13 +587,13 @@
                 c.getRefName(),
                 c.getOldId(),
                 c.getNewId());
-            if (isHead(c)) {
+            if (isHead(c) || isConfig(c)) {
               autoCloseChanges(c);
             }
             break;
 
           case UPDATE_NONFASTFORWARD:
-            if (isHead(c)) {
+            if (isHead(c) || isConfig(c)) {
               autoCloseChanges(c);
             }
             break;
@@ -691,7 +694,7 @@
           log.error(String.format(
               "Cannot add patch set to %d of %s",
               e.getKey().get(), project.getName()), err);
-        } catch (OrmException err) {
+        } catch (InsertException err) {
           reject(replace.inputCommand, "internal server error");
           log.error(String.format(
               "Cannot add patch set to %d of %s",
@@ -725,7 +728,7 @@
     }
 
     try {
-      List<CheckedFuture<?, OrmException>> futures = Lists.newArrayList();
+      List<CheckedFuture<?, InsertException>> futures = Lists.newArrayList();
       for (ReplaceRequest replace : replaceByChange.values()) {
         if (magicBranch != null && replace.inputCommand == magicBranch.cmd) {
           futures.add(replace.insertPatchSet());
@@ -736,12 +739,12 @@
         futures.add(create.insertChange());
       }
 
-      for (CheckedFuture<?, OrmException> f : futures) {
+      for (CheckedFuture<?, InsertException> f : futures) {
         f.checkedGet();
       }
       magicBranch.cmd.setResult(OK);
-    } catch (OrmException err) {
-      log.error("Can't insert changes for " + project.getName(), err);
+    } catch (InsertException err) {
+      log.error("Can't insert change/patchset for " + project.getName(), err);
       reject(magicBranch.cmd, "internal server error");
     } catch (IOException err) {
       log.error("Can't read commits for " + project.getName(), err);
@@ -1389,7 +1392,7 @@
       }
 
       List<ChangeLookup> pending = Lists.newArrayList();
-      final Set<Change.Key> newChangeIds = new HashSet<Change.Key>();
+      final Set<Change.Key> newChangeIds = new HashSet<>();
       for (;;) {
         final RevCommit c = walk.next();
         if (c == null) {
@@ -1545,7 +1548,7 @@
           ins.getPatchSet().getRefName());
     }
 
-    CheckedFuture<Void, OrmException> insertChange() throws IOException {
+    CheckedFuture<Void, InsertException> insertChange() throws IOException {
       rp.getRevWalk().parseBody(commit);
 
       final Thread caller = Thread.currentThread();
@@ -1569,7 +1572,7 @@
           return null;
         }
       }));
-      return Futures.makeChecked(future, ORM_EXCEPTION);
+      return Futures.makeChecked(future, INSERT_EXCEPTION);
     }
 
     private void insertChange(ReviewDb db) throws OrmException, IOException {
@@ -1798,7 +1801,7 @@
 
       for (final Ref r : rp.getRepository().getRefDatabase()
           .getRefs("refs/changes").values()) {
-        if (r.getObjectId().equals(inputCommand.getNewId())) {
+        if (r.getObjectId().equals(newCommit)) {
           reject(inputCommand, "commit already exists (in the project)");
           return false;
         }
@@ -1873,7 +1876,7 @@
       return true;
     }
 
-    CheckedFuture<PatchSet.Id, OrmException> insertPatchSet()
+    CheckedFuture<PatchSet.Id, InsertException> insertPatchSet()
         throws IOException {
       rp.getRevWalk().parseBody(newCommit);
 
@@ -1900,7 +1903,7 @@
           }
         }
       }));
-      return Futures.makeChecked(future, ORM_EXCEPTION);
+      return Futures.makeChecked(future, INSERT_EXCEPTION);
     }
 
     PatchSet.Id insertPatchSet(ReviewDb db) throws OrmException, IOException {
@@ -2217,7 +2220,7 @@
       final SetMultimap<ObjectId, Ref> byCommit = changeRefsById();
       final Map<Change.Key, Change.Id> byKey = openChangesByKey(
           new Branch.NameKey(project.getNameKey(), cmd.getRefName()));
-      final List<ReplaceRequest> toClose = new ArrayList<ReplaceRequest>();
+      final List<ReplaceRequest> toClose = new ArrayList<>();
       RevCommit c;
       while ((c = rw.next()) != null) {
         final Set<Ref> refs = byCommit.get(c.copy());
@@ -2266,6 +2269,8 @@
               codeReviewCommit, rw, repo, project, new ArrayList<Change>(),
               new HashMap<Change.Id, CodeReviewCommit>());
       subOp.update();
+    } catch (InsertException e) {
+      log.error("Can't insert patchset", e);
     } catch (IOException e) {
       log.error("Can't scan for changes to close", e);
     } catch (OrmException e) {
@@ -2323,7 +2328,7 @@
 
   private Map<Change.Key, Change.Id> openChangesByKey(Branch.NameKey branch)
       throws OrmException {
-    final Map<Change.Key, Change.Id> r = new HashMap<Change.Key, Change.Id>();
+    final Map<Change.Key, Change.Id> r = new HashMap<>();
     for (Change c : db.changes().byBranchOpenAll(branch)) {
       r.put(c.getKey(), c.getId());
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReloadSubmitQueueOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReloadSubmitQueueOp.java
index bcc2107..850f2be 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReloadSubmitQueueOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReloadSubmitQueueOp.java
@@ -46,7 +46,7 @@
   }
 
   public void run() {
-    final HashSet<Branch.NameKey> pending = new HashSet<Branch.NameKey>();
+    final HashSet<Branch.NameKey> pending = new HashSet<>();
     try {
       final ReviewDb c = schema.open();
       try {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/RenameGroupOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/RenameGroupOp.java
index 7490006..2b3994c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/RenameGroupOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/RenameGroupOp.java
@@ -69,7 +69,7 @@
     this.uuid = uuid;
     this.oldName = oldName;
     this.newName = newName;
-    this.retryOn = new ArrayList<Project.NameKey>();
+    this.retryOn = new ArrayList<>();
   }
 
   @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java
index 5424887..0279244 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java
@@ -110,7 +110,7 @@
     this.repoManager = repoManager;
     this.gitRefUpdated = gitRefUpdated;
 
-    updatedSubscribers = new HashSet<Branch.NameKey>();
+    updatedSubscribers = new HashSet<>();
   }
 
   public void update() throws SubmoduleException {
@@ -151,14 +151,13 @@
                 destBranch.get());
 
         final Set<SubmoduleSubscription> oldSubscriptions =
-            new HashSet<SubmoduleSubscription>(schema.submoduleSubscriptions()
+            new HashSet<>(schema.submoduleSubscriptions()
                 .bySuperProject(destBranch).toList());
         final List<SubmoduleSubscription> newSubscriptions =
             new SubmoduleSectionParser(bbc, thisServer, target, repoManager)
                 .parseAllSections();
 
-        final Set<SubmoduleSubscription> alreadySubscribeds =
-            new HashSet<SubmoduleSubscription>();
+        final Set<SubmoduleSubscription> alreadySubscribeds = new HashSet<>();
         for (SubmoduleSubscription s : newSubscriptions) {
           if (oldSubscriptions.contains(s)) {
             alreadySubscribeds.add(s);
@@ -232,12 +231,10 @@
                 + s.toString());
           } else {
 
-            Map<Branch.NameKey, ObjectId> modules =
-                new HashMap<Branch.NameKey, ObjectId>(1);
+            Map<Branch.NameKey, ObjectId> modules = new HashMap<>(1);
             modules.put(updatedBranch, mergedCommit);
 
-            Map<Branch.NameKey, String> paths =
-                new HashMap<Branch.NameKey, String>(1);
+            Map<Branch.NameKey, String> paths = new HashMap<>(1);
             paths.put(updatedBranch, s.getPath());
 
             try {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/TagMatcher.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/TagMatcher.java
index b63378f..e550927 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/TagMatcher.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/TagMatcher.java
@@ -27,8 +27,8 @@
 
 class TagMatcher {
   final BitSet mask = new BitSet();
-  final List<Ref> newRefs = new ArrayList<Ref>();
-  final List<LostRef> lostRefs = new ArrayList<LostRef>();
+  final List<Ref> newRefs = new ArrayList<>();
+  final List<LostRef> lostRefs = new ArrayList<>();
   final TagSetHolder holder;
   final TagCache cache;
   final Repository db;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/TagSet.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/TagSet.java
index 3eb9273..761d5d6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/TagSet.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/TagSet.java
@@ -51,8 +51,8 @@
 
   TagSet(Project.NameKey projectName) {
     this.projectName = projectName;
-    this.refs = new HashMap<String, CachedRef>();
-    this.tags = new ObjectIdOwnerMap<Tag>();
+    this.refs = new HashMap<>();
+    this.tags = new ObjectIdOwnerMap<>();
   }
 
   Tag lookupTag(AnyObjectId id) {
@@ -238,7 +238,7 @@
     // Gerrit Code Review server, perhaps about 50% of new references.
     // Since a complete rebuild is so costly, try this approach first.
 
-    Map<ObjectId, Integer> byObj = new HashMap<ObjectId, Integer>();
+    Map<ObjectId, Integer> byObj = new HashMap<>();
     for (CachedRef r : old.refs.values()) {
       ObjectId id = r.get();
       if (!byObj.containsKey(id)) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/VisibleRefFilter.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/VisibleRefFilter.java
index 343b49c..62d80fa 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/VisibleRefFilter.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/VisibleRefFilter.java
@@ -77,8 +77,8 @@
     }
 
     final Set<Change.Id> visibleChanges = visibleChanges();
-    final Map<String, Ref> result = new HashMap<String, Ref>();
-    final List<Ref> deferredTags = new ArrayList<Ref>();
+    final Map<String, Ref> result = new HashMap<>();
+    final List<Ref> deferredTags = new ArrayList<>();
 
     for (Ref ref : refs.values()) {
       if (ref.getName().startsWith(RefNames.REFS_CACHE_AUTOMERGE)) {
@@ -149,7 +149,7 @@
 
     final Project project = projectCtl.getProject();
     try {
-      final Set<Change.Id> visibleChanges = new HashSet<Change.Id>();
+      final Set<Change.Id> visibleChanges = new HashSet<>();
       for (Change change : changeCache.get(project.getNameKey())) {
         if (projectCtl.controlFor(change).isVisible(reviewDb)) {
           visibleChanges.add(change.getId());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java
index 6e274a1..8c11aec 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java
@@ -90,10 +90,14 @@
   private final CopyOnWriteArrayList<Executor> queues;
 
   @Inject
-  WorkQueue(final IdGenerator idGenerator, @GerritServerConfig final Config cfg) {
+  WorkQueue(IdGenerator idGenerator, @GerritServerConfig Config cfg) {
+    this(idGenerator, cfg.getInt("execution", "defaultThreadPoolSize", 1));
+  }
+
+  public WorkQueue(IdGenerator idGenerator, int defaultThreadPoolSize) {
     this.idGenerator = idGenerator;
-    this.queues = new CopyOnWriteArrayList<Executor>();
-    defaultQueueSize = cfg.getInt("execution", "defaultThreadPoolSize", 1);
+    this.queues = new CopyOnWriteArrayList<>();
+    this.defaultQueueSize = defaultThreadPoolSize;
   }
 
   /** Get the default work queue, for miscellaneous tasks. */
@@ -115,7 +119,7 @@
 
   /** Get all of the tasks currently scheduled in any work queue. */
   public List<Task<?>> getTasks() {
-    final List<Task<?>> r = new ArrayList<Task<?>>();
+    final List<Task<?>> r = new ArrayList<>();
     for (final Executor e : queues) {
       e.addAllTo(r);
     }
@@ -182,7 +186,7 @@
         }
       });
 
-      all = new ConcurrentHashMap<Integer, Task<?>>( //
+      all = new ConcurrentHashMap<>( //
           corePoolSize << 1, // table size
           0.75f, // load factor
           corePoolSize + 4 // concurrency level
@@ -203,9 +207,9 @@
         Task<V> task;
 
         if (runnable instanceof ProjectRunnable) {
-          task = new ProjectTask<V>((ProjectRunnable) runnable, r, this, id);
+          task = new ProjectTask<>((ProjectRunnable) runnable, r, this, id);
         } else {
-          task = new Task<V>(runnable, r, this, id);
+          task = new Task<>(runnable, r, this, id);
         }
 
         if (all.putIfAbsent(task.getTaskId(), task) == null) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/CherryPick.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/CherryPick.java
index 18df4c1..08421ca 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/CherryPick.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/CherryPick.java
@@ -56,7 +56,7 @@
 
     this.patchSetInfoFactory = patchSetInfoFactory;
     this.gitRefUpdated = gitRefUpdated;
-    this.newCommits = new HashMap<Change.Id, CodeReviewCommit>();
+    this.newCommits = new HashMap<>();
   }
 
   @Override
@@ -179,7 +179,7 @@
 
       final List<PatchSetApproval> approvals = Lists.newArrayList();
       for (PatchSetApproval a
-          : args.approvalsUtil.byPatchSet(args.db, n.notes(), n.getPatchsetId())) {
+          : args.approvalsUtil.byPatchSet(args.db, n.getControl(), n.getPatchsetId())) {
         approvals.add(new PatchSetApproval(ps.getId(), a));
       }
       args.db.patchSetApprovals().insert(approvals);
@@ -212,7 +212,7 @@
   private static void insertAncestors(ReviewDb db, PatchSet.Id id, RevCommit src)
       throws OrmException {
     final int cnt = src.getParentCount();
-    List<PatchSetAncestor> toInsert = new ArrayList<PatchSetAncestor>(cnt);
+    List<PatchSetAncestor> toInsert = new ArrayList<>(cnt);
     for (int p = 0; p < cnt; p++) {
       PatchSetAncestor a;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/RebaseIfNecessary.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/RebaseIfNecessary.java
index a97b3fd..c38f5f21 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/RebaseIfNecessary.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/RebaseIfNecessary.java
@@ -52,7 +52,7 @@
     super(args);
     this.patchSetInfoFactory = patchSetInfoFactory;
     this.rebaseChange = rebaseChange;
-    this.newCommits = new HashMap<Change.Id, CodeReviewCommit>();
+    this.newCommits = new HashMap<>();
     this.committerIdent = committerIdent;
   }
 
@@ -96,7 +96,7 @@
 
             List<PatchSetApproval> approvals = Lists.newArrayList();
             for (PatchSetApproval a : args.approvalsUtil.byPatchSet(
-                args.db, n.notes(), n.getPatchsetId())) {
+                args.db, n.getControl(), n.getPatchsetId())) {
               approvals.add(new PatchSetApproval(newPatchSet.getId(), a));
             }
             // rebaseChange.rebase() may already have copied some approvals,
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/validators/CommitValidators.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/validators/CommitValidators.java
index 1bf754a..a77938e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/validators/CommitValidators.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/validators/CommitValidators.java
@@ -92,8 +92,7 @@
   public List<CommitValidationMessage> validateForReceiveCommits(
       CommitReceivedEvent receiveEvent) throws CommitValidationException {
 
-    List<CommitValidationListener> validators =
-        new LinkedList<CommitValidationListener>();
+    List<CommitValidationListener> validators = new LinkedList<>();
 
     validators.add(new UploadMergesPermissionValidator(refControl));
     validators.add(new AmendedGerritMergeCommitValidationListener(
@@ -110,8 +109,7 @@
     validators.add(new ConfigValidator(refControl, repo));
     validators.add(new PluginCommitValidationListener(commitValidationListeners));
 
-    List<CommitValidationMessage> messages =
-        new LinkedList<CommitValidationMessage>();
+    List<CommitValidationMessage> messages = new LinkedList<>();
 
     try {
       for (CommitValidationListener commitValidator : validators) {
@@ -128,8 +126,7 @@
   public List<CommitValidationMessage> validateForGerritCommits(
       CommitReceivedEvent receiveEvent) throws CommitValidationException {
 
-    List<CommitValidationListener> validators =
-        new LinkedList<CommitValidationListener>();
+    List<CommitValidationListener> validators = new LinkedList<>();
 
     validators.add(new UploadMergesPermissionValidator(refControl));
     validators.add(new AmendedGerritMergeCommitValidationListener(
@@ -145,8 +142,7 @@
     validators.add(new ConfigValidator(refControl, repo));
     validators.add(new PluginCommitValidationListener(commitValidationListeners));
 
-    List<CommitValidationMessage> messages =
-        new LinkedList<CommitValidationMessage>();
+    List<CommitValidationMessage> messages = new LinkedList<>();
 
     try {
       for (CommitValidationListener commitValidator : validators) {
@@ -181,8 +177,7 @@
         CommitReceivedEvent receiveEvent) throws CommitValidationException {
       final List<String> idList = receiveEvent.commit.getFooterLines(CHANGE_ID);
 
-      List<CommitValidationMessage> messages =
-          new LinkedList<CommitValidationMessage>();
+      List<CommitValidationMessage> messages = new LinkedList<>();
 
       if (idList.isEmpty()) {
         if (projectControl.getProjectState().isRequireChangeID()) {
@@ -321,8 +316,7 @@
       IdentifiedUser currentUser = (IdentifiedUser) refControl.getCurrentUser();
 
       if (RefNames.REFS_CONFIG.equals(refControl.getRefName())) {
-        List<CommitValidationMessage> messages =
-            new LinkedList<CommitValidationMessage>();
+        List<CommitValidationMessage> messages = new LinkedList<>();
 
         try {
           ProjectConfig cfg =
@@ -381,8 +375,7 @@
     @Override
     public List<CommitValidationMessage> onCommitReceived(
         CommitReceivedEvent receiveEvent) throws CommitValidationException {
-      List<CommitValidationMessage> messages =
-          new LinkedList<CommitValidationMessage>();
+      List<CommitValidationMessage> messages = new LinkedList<>();
 
       for (CommitValidationListener validator : commitValidationListeners) {
         try {
@@ -452,8 +445,7 @@
 
       if (!currentUser.getEmailAddresses().contains(author.getEmailAddress())
           && !refControl.canForgeAuthor()) {
-        List<CommitValidationMessage> messages =
-            new LinkedList<CommitValidationMessage>();
+        List<CommitValidationMessage> messages = new LinkedList<>();
 
         messages.add(getInvalidEmailError(receiveEvent.commit, "author", author,
             currentUser, canonicalWebUrl));
@@ -483,8 +475,7 @@
       if (!currentUser.getEmailAddresses()
           .contains(committer.getEmailAddress())
           && !refControl.canForgeCommitter()) {
-        List<CommitValidationMessage> messages =
-            new LinkedList<CommitValidationMessage>();
+        List<CommitValidationMessage> messages = new LinkedList<>();
         messages.add(getInvalidEmailError(receiveEvent.commit, "committer", committer,
             currentUser, canonicalWebUrl));
         throw new CommitValidationException("invalid committer", messages);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java
index 170c346..91a0ec5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java
@@ -67,7 +67,7 @@
 
   @Option(name = "--project", aliases = {"-p"},
       usage = "projects for which the groups should be listed")
-  private final List<ProjectControl> projects = new ArrayList<ProjectControl>();
+  private final List<ProjectControl> projects = new ArrayList<>();
 
   @Option(name = "--visible-to-all", usage = "to list only groups that are visible to all registered users")
   private boolean visibleToAll;
@@ -87,6 +87,12 @@
     groupsToInspect.add(id);
   }
 
+  @Option(name = "--limit", aliases = {"-n"}, metaVar = "CNT", usage = "maximum number of groups to list")
+  private int limit;
+
+  @Option(name = "-S", metaVar = "CNT", usage = "number of groups to skip")
+  private int start;
+
   @Option(name = "-m", metaVar = "MATCH", usage = "match group substring")
   private String matchSubstring;
 
@@ -168,7 +174,15 @@
           groupList = filterGroups(groupCache.all());
         }
         groupInfos = Lists.newArrayListWithCapacity(groupList.size());
+        int found = 0;
+        int foundIndex = 0;
         for (AccountGroup group : groupList) {
+          if (foundIndex++ < start) {
+            continue;
+          }
+          if (limit > 0 && ++found > limit) {
+            break;
+          }
           groupInfos.add(json.addOptions(options).format(
               GroupDescriptions.forAccountGroup(group)));
         }
@@ -180,11 +194,19 @@
   private List<GroupInfo> getGroupsOwnedBy(IdentifiedUser user)
       throws OrmException {
     List<GroupInfo> groups = Lists.newArrayList();
+    int found = 0;
+    int foundIndex = 0;
     for (AccountGroup g : filterGroups(groupCache.all())) {
       GroupControl ctl = groupControlFactory.controlFor(g);
       try {
         if (genericGroupControlFactory.controlFor(user, g.getGroupUUID())
             .isOwner()) {
+          if (foundIndex++ < start) {
+            continue;
+          }
+          if (limit > 0 && ++found > limit) {
+            break;
+          }
           groups.add(json.addOptions(options).format(ctl.getGroup()));
         }
       } catch (NoSuchGroupException e) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeSchemas.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeSchemas.java
index bd37408..1a628d3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeSchemas.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeSchemas.java
@@ -220,7 +220,7 @@
 
 
   private static Schema<ChangeData> release(Collection<FieldDef<ChangeData, ?>> fields) {
-    return new Schema<ChangeData>(true, fields);
+    return new Schema<>(true, fields);
   }
 
   @SafeVarargs
@@ -231,7 +231,7 @@
   @SafeVarargs
   @SuppressWarnings("unused")
   private static Schema<ChangeData> developer(FieldDef<ChangeData, ?>... fields) {
-    return new Schema<ChangeData>(false, Arrays.asList(fields));
+    return new Schema<>(false, Arrays.asList(fields));
   }
 
   public static final ImmutableMap<Integer, Schema<ChangeData>> ALL;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexCollection.java
index 2558cb4..2380c76 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexCollection.java
@@ -35,7 +35,7 @@
   @VisibleForTesting
   public IndexCollection() {
     this.writeIndexes = Lists.newCopyOnWriteArrayList();
-    this.searchIndex = new AtomicReference<ChangeIndex>();
+    this.searchIndex = new AtomicReference<>();
   }
 
   /** @return the current search index version. */
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/Schema.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/Schema.java
index c3a60d0..0de1379 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/Schema.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/Schema.java
@@ -113,9 +113,9 @@
             if (v == null) {
               return null;
             } else if (f.isRepeatable()) {
-              return new Values<T>(f, (Iterable<?>) v);
+              return new Values<>(f, (Iterable<?>) v);
             } else {
-              return new Values<T>(f, Collections.singleton(v));
+              return new Values<>(f, Collections.singleton(v));
             }
           }
         }).filter(Predicates.notNull());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java
index 4e51a73..d38c5a3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java
@@ -98,7 +98,7 @@
     formatChange();
     appendText(velocifyFile("ChangeFooter.vm"));
     try {
-      TreeSet<String> names = new TreeSet<String>();
+      TreeSet<String> names = new TreeSet<>();
       for (Account.Id who : changeData.reviewers().values()) {
         names.add(getNameEmailFor(who));
       }
@@ -338,7 +338,7 @@
 
   /** Find all users who are authors of any part of this change. */
   protected Set<Account.Id> getAuthors() {
-    Set<Account.Id> authors = new HashSet<Account.Id>();
+    Set<Account.Id> authors = new HashSet<>();
 
     authors.add(change.getOwner());
     if (patchSet != null) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java
index cb92b0f..32a95dd 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java
@@ -65,7 +65,7 @@
   public void setPatchLineComments(final List<PatchLineComment> plc) {
     inlineComments = plc;
 
-    Set<String> paths = new HashSet<String>();
+    Set<String> paths = new HashSet<>();
     for (PatchLineComment c : plc) {
       Patch.Key p = c.getKey().getParentKey();
       if (!Patch.COMMIT_MSG.equals(p.getFileName())) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailHeader.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailHeader.java
index 6492a5e..d4dce70 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailHeader.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailHeader.java
@@ -114,7 +114,7 @@
   }
 
   public static class AddressList extends EmailHeader {
-    private final List<Address> list = new ArrayList<Address>();
+    private final List<Address> list = new ArrayList<>();
 
     public AddressList() {
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/MailUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/MailUtil.java
index ac367ef..26cccb8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/MailUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/MailUtil.java
@@ -86,14 +86,14 @@
     private final Set<Account.Id> cc;
 
     public MailRecipients() {
-      this.reviewers = new HashSet<Account.Id>();
-      this.cc = new HashSet<Account.Id>();
+      this.reviewers = new HashSet<>();
+      this.cc = new HashSet<>();
     }
 
     public MailRecipients(final Set<Account.Id> reviewers,
         final Set<Account.Id> cc) {
-      this.reviewers = new HashSet<Account.Id>(reviewers);
-      this.cc = new HashSet<Account.Id>(cc);
+      this.reviewers = new HashSet<>(reviewers);
+      this.cc = new HashSet<>(cc);
     }
 
     public void add(final MailRecipients recipients) {
@@ -111,14 +111,13 @@
     }
 
     public Set<Account.Id> getCcOnly() {
-      final Set<Account.Id> cc = new HashSet<Account.Id>(this.cc);
+      final Set<Account.Id> cc = new HashSet<>(this.cc);
       cc.removeAll(reviewers);
       return Collections.unmodifiableSet(cc);
     }
 
     public Set<Account.Id> getAll() {
-      final Set<Account.Id> all =
-          new HashSet<Account.Id>(reviewers.size() + cc.size());
+      final Set<Account.Id> all = new HashSet<>(reviewers.size() + cc.size());
       all.addAll(reviewers);
       all.addAll(cc);
       return Collections.unmodifiableSet(all);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergedSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergedSender.java
index 07a5f9a..5cb1ba1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergedSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergedSender.java
@@ -62,7 +62,7 @@
       Table<Account.Id, String, PatchSetApproval> pos = HashBasedTable.create();
       Table<Account.Id, String, PatchSetApproval> neg = HashBasedTable.create();
       for (PatchSetApproval ca : args.approvalsUtil.byPatchSet(
-            args.db.get(), changeData.notes(), patchSet.getId())) {
+            args.db.get(), changeData.changeControl(), patchSet.getId())) {
         LabelType lt = labelTypes.byLabel(ca.getLabelId());
         if (lt == null) {
           continue;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/NewChangeSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/NewChangeSender.java
index 9ff0dbd..0dbcbe0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/NewChangeSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/NewChangeSender.java
@@ -26,8 +26,8 @@
 
 /** Sends an email alerting a user to a new change for them to review. */
 public abstract class NewChangeSender extends ChangeEmail {
-  private final Set<Account.Id> reviewers = new HashSet<Account.Id>();
-  private final Set<Account.Id> extraCC = new HashSet<Account.Id>();
+  private final Set<Account.Id> reviewers = new HashSet<>();
+  private final Set<Account.Id> extraCC = new HashSet<>();
 
   protected NewChangeSender(EmailArguments ea, Change c) {
     super(ea, c, "newchange");
@@ -61,7 +61,7 @@
     if (reviewers.isEmpty()) {
       return null;
     }
-    List<String> names = new ArrayList<String>();
+    List<String> names = new ArrayList<>();
     for (Account.Id id : reviewers) {
       names.add(getNameFor(id));
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/OutgoingEmail.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/OutgoingEmail.java
index dc09a9c..32f74bc 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/OutgoingEmail.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/OutgoingEmail.java
@@ -52,7 +52,7 @@
   private static final String HDR_CC = "CC";
 
   protected String messageClass;
-  private final HashSet<Account.Id> rcptTo = new HashSet<Account.Id>();
+  private final HashSet<Account.Id> rcptTo = new HashSet<>();
   private final Map<String, EmailHeader> headers;
   private final Set<Address> smtpRcptTo = Sets.newHashSet();
   private Address smtpFromAddress;
@@ -66,7 +66,7 @@
   protected OutgoingEmail(EmailArguments ea, String mc) {
     args = ea;
     messageClass = mc;
-    headers = new LinkedHashMap<String, EmailHeader>();
+    headers = new LinkedHashMap<>();
   }
 
   public void setFrom(final Account.Id id) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ProjectWatch.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ProjectWatch.java
index 04c3f9f..3d16372 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ProjectWatch.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ProjectWatch.java
@@ -64,7 +64,7 @@
   /** Returns all watchers that are relevant */
   public final Watchers getWatchers(NotifyType type) throws OrmException {
     Watchers matching = new Watchers();
-    Set<Account.Id> projectWatchers = new HashSet<Account.Id>();
+    Set<Account.Id> projectWatchers = new HashSet<>();
 
     for (AccountProjectWatch w : args.db.get().accountProjectWatches()
         .byProject(project)) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplacePatchSetSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplacePatchSetSender.java
index d80fb50..8412d22 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplacePatchSetSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplacePatchSetSender.java
@@ -33,8 +33,8 @@
     public ReplacePatchSetSender create(Change change);
   }
 
-  private final Set<Account.Id> reviewers = new HashSet<Account.Id>();
-  private final Set<Account.Id> extraCC = new HashSet<Account.Id>();
+  private final Set<Account.Id> reviewers = new HashSet<>();
+  private final Set<Account.Id> extraCC = new HashSet<>();
 
   @Inject
   public ReplacePatchSetSender(EmailArguments ea, @Assisted Change c) {
@@ -74,7 +74,7 @@
     if (reviewers.isEmpty()) {
       return null;
     }
-    List<String> names = new ArrayList<String>();
+    List<String> names = new ArrayList<>();
     for (Account.Id id : reviewers) {
       names.add(getNameFor(id));
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/SmtpEmailSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/SmtpEmailSender.java
index f16cb5a..b1c5955 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/SmtpEmailSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/SmtpEmailSender.java
@@ -107,7 +107,7 @@
     smtpUser = cfg.getString("sendemail", null, "smtpuser");
     smtpPass = cfg.getString("sendemail", null, "smtppass");
 
-    Set<String> rcpt = new HashSet<String>();
+    Set<String> rcpt = new HashSet<>();
     for (String addr : cfg.getStringList("sendemail", null, "allowrcpt")) {
       rcpt.add(addr);
     }
@@ -152,7 +152,7 @@
     }
 
     final Map<String, EmailHeader> hdrs =
-        new LinkedHashMap<String, EmailHeader>(callerHeaders);
+        new LinkedHashMap<>(callerHeaders);
     setMissingHeader(hdrs, "MIME-Version", "1.0");
     setMissingHeader(hdrs, "Content-Type", "text/plain; charset=UTF-8");
     setMissingHeader(hdrs, "Content-Transfer-Encoding", "8bit");
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/NotesMigration.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/NotesMigration.java
index c9ac8de..5321046 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/NotesMigration.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/NotesMigration.java
@@ -14,8 +14,6 @@
 
 package com.google.gerrit.server.notedb;
 
-import static com.google.common.base.Preconditions.checkArgument;
-
 import com.google.common.annotations.VisibleForTesting;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.inject.Inject;
@@ -36,7 +34,7 @@
   static NotesMigration allEnabled() {
     Config cfg = new Config();
     cfg.setBoolean("notedb", null, "write", true);
-    //cfg.setBoolean("notedb", "patchSetApprovals", "read", true);
+    cfg.setBoolean("notedb", "patchSetApprovals", "read", true);
     return new NotesMigration(cfg);
   }
 
@@ -48,8 +46,6 @@
     write = cfg.getBoolean("notedb", null, "write", false);
     readPatchSetApprovals =
         cfg.getBoolean("notedb", "patchSetApprovals", "read", false);
-    checkArgument(!readPatchSetApprovals,
-        "notedb.readPatchSetApprovals not yet supported");
   }
 
   public boolean write() {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineLoader.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineLoader.java
index 52cba09..4961bef 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineLoader.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineLoader.java
@@ -78,7 +78,7 @@
   }
 
   static IntraLineDiff compute(IntraLineDiffKey key) throws Exception {
-    List<Edit> edits = new ArrayList<Edit>(key.getEdits());
+    List<Edit> edits = new ArrayList<>(key.getEdits());
     Text aContent = key.getTextA();
     Text bContent = key.getTextB();
     combineLineEdits(edits, aContent, bContent);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineWorkerPool.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineWorkerPool.java
index 5c6338fe..49ae950 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineWorkerPool.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineWorkerPool.java
@@ -45,7 +45,7 @@
     int workers = cfg.getInt(
         "cache", PatchListCacheImpl.INTRA_NAME, "maxIdleWorkers",
         Runtime.getRuntime().availableProcessors() * 3 / 2);
-    workerPool = new ArrayBlockingQueue<Worker>(workers, true /* fair */);
+    workerPool = new ArrayBlockingQueue<>(workers, true /* fair */);
   }
 
   Worker acquire() {
@@ -73,8 +73,8 @@
     private final ArrayBlockingQueue<Result> result;
 
     Worker() {
-      input = new ArrayBlockingQueue<Input>(1);
-      result = new ArrayBlockingQueue<Result>(1);
+      input = new ArrayBlockingQueue<>(1);
+      result = new ArrayBlockingQueue<>(1);
 
       setName("IntraLineDiff-" + count.getAndIncrement());
       setDaemon(true);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchList.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchList.java
index 59e3050..7d44912 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchList.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchList.java
@@ -127,7 +127,7 @@
    *        how the cache is keyed versus how the database is keyed.
    */
   public List<Patch> toPatchList(final PatchSet.Id setId) {
-    final ArrayList<Patch> r = new ArrayList<Patch>(patches.length);
+    final ArrayList<Patch> r = new ArrayList<>(patches.length);
     for (final PatchListEntry e : patches) {
       r.add(e.toPatch(setId));
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListEntry.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListEntry.java
index 852165c..31f5e96 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListEntry.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListEntry.java
@@ -168,7 +168,7 @@
 
   public List<String> getHeaderLines() {
     final IntList m = RawParseUtils.lineMap(header, 0, header.length);
-    final List<String> headerLines = new ArrayList<String>(m.size() - 1);
+    final List<String> headerLines = new ArrayList<>(m.size() - 1);
     for (int i = 1; i < m.size() - 1; i++) {
       final int b = m.get(i);
       int e = m.get(i + 1);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListLoader.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListLoader.java
index 2cda334..f704ea2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListLoader.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListLoader.java
@@ -311,7 +311,7 @@
 
         MergeFormatter fmt = new MergeFormatter();
         Map<String, MergeResult<? extends Sequence>> r = m.getMergeResults();
-        Map<String, ObjectId> resolved = new HashMap<String, ObjectId>();
+        Map<String, ObjectId> resolved = new HashMap<>();
         for (Map.Entry<String, MergeResult<? extends Sequence>> entry : r.entrySet()) {
           MergeResult<? extends Sequence> p = entry.getValue();
           TemporaryBuffer buf = new TemporaryBuffer.LocalFile(10 * 1024 * 1024);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptBuilder.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
index 0db7dee..0c98ccf 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
@@ -136,7 +136,7 @@
     a.resolve(null, aId);
     b.resolve(a, bId);
 
-    edits = new ArrayList<Edit>(content.getEdits());
+    edits = new ArrayList<>(content.getEdits());
 
     if (!isModify(content)) {
       intralineDifferenceIsPossible = false;
@@ -148,7 +148,7 @@
       if (d != null) {
         switch (d.getStatus()) {
           case EDIT_LIST:
-            edits = new ArrayList<Edit>(d.getEdits());
+            edits = new ArrayList<>(d.getEdits());
             break;
 
           case DISABLED:
@@ -171,7 +171,9 @@
       }
     }
 
-    ensureCommentsVisible(comments);
+    if (comments != null) {
+      ensureCommentsVisible(comments);
+    }
 
     boolean hugeFile = false;
     if (a.mode == FileMode.GITLINK || b.mode == FileMode.GITLINK) {
@@ -185,7 +187,7 @@
       for (int i = 0; i < a.size(); i++) {
         a.addLine(i);
       }
-      edits = new ArrayList<Edit>(1);
+      edits = new ArrayList<>(1);
       edits.add(new Edit(a.size(), a.size()));
 
     } else {
@@ -269,7 +271,7 @@
     // correct hunks from this, but because the Edit is empty they will not
     // style it specially.
     //
-    final List<Edit> empty = new ArrayList<Edit>();
+    final List<Edit> empty = new ArrayList<>();
     int lastLine;
 
     lastLine = -1;
@@ -450,7 +452,9 @@
 
           id = tw != null ? tw.getObjectId(0) : ObjectId.zeroId();
           mode = tw != null ? tw.getFileMode(0) : FileMode.MISSING;
-          reuse = other != null && other.id.equals(id) && other.mode == mode;
+          reuse = other != null
+              && other.id.equals(id)
+              && (other.mode == mode || isBothFile(other.mode, mode));
 
           if (reuse) {
             srcContent = other.srcContent;
@@ -514,4 +518,9 @@
       return TreeWalk.forPath(reader, path, tree);
     }
   }
+
+  private static boolean isBothFile(FileMode a, FileMode b) {
+    return (a.getBits() & FileMode.TYPE_FILE) == FileMode.TYPE_FILE
+        && (b.getBits() & FileMode.TYPE_FILE) == FileMode.TYPE_FILE;
+  }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptFactory.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptFactory.java
index ed4470a..4be9e7d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptFactory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptFactory.java
@@ -79,6 +79,8 @@
   private final AccountDiffPreference diffPrefs;
 
   private final Change.Id changeId;
+  private boolean loadHistory = true;
+  private boolean loadComments = true;
 
   private Change change;
   private Project.NameKey projectKey;
@@ -113,6 +115,14 @@
     changeId = patchSetB.getParentKey();
   }
 
+  public void setLoadHistory(boolean load) {
+    loadHistory = load;
+  }
+
+  public void setLoadComments(boolean load) {
+    loadComments = load;
+  }
+
   @Override
   public PatchScript call() throws OrmException, NoSuchChangeException,
       LargeObjectException {
@@ -149,7 +159,7 @@
           content.getOldName(), //
           content.getNewName());
 
-        return b.toPatchScript(content, comments, history);
+      return b.toPatchScript(content, comments, history);
     } catch (PatchListNotAvailableException e) {
       throw new NoSuchChangeException(changeId, e);
     } catch (IOException e) {
@@ -212,93 +222,96 @@
 
   private void loadCommentsAndHistory(final ChangeType changeType,
       final String oldName, final String newName) throws OrmException {
-    history = new ArrayList<Patch>();
-    comments = new CommentDetail(psa, psb);
+    final Map<Patch.Key, Patch> byKey = new HashMap<>();
 
-    final Map<Patch.Key, Patch> byKey = new HashMap<Patch.Key, Patch>();
-    final AccountInfoCacheFactory aic = aicFactory.create();
-
-    // This seems like a cheap trick. It doesn't properly account for a
-    // file that gets renamed between patch set 1 and patch set 2. We
-    // will wind up packing the wrong Patch object because we didn't do
-    // proper rename detection between the patch sets.
-    //
-    for (final PatchSet ps : db.patchSets().byChange(changeId)) {
-      if (!control.isPatchVisible(ps, db)) {
-        continue;
-      }
-      String name = fileName;
-      if (psa != null) {
-        switch (changeType) {
-          case COPIED:
-          case RENAMED:
-            if (ps.getId().equals(psa)) {
-              name = oldName;
-            }
-            break;
-
-          case MODIFIED:
-          case DELETED:
-          case ADDED:
-          case REWRITE:
-            break;
+    if (loadHistory) {
+      // This seems like a cheap trick. It doesn't properly account for a
+      // file that gets renamed between patch set 1 and patch set 2. We
+      // will wind up packing the wrong Patch object because we didn't do
+      // proper rename detection between the patch sets.
+      //
+      history = new ArrayList<>();
+      for (final PatchSet ps : db.patchSets().byChange(changeId)) {
+        if (!control.isPatchVisible(ps, db)) {
+          continue;
         }
-      }
-
-      final Patch p = new Patch(new Patch.Key(ps.getId(), name));
-      history.add(p);
-      byKey.put(p.getKey(), p);
-    }
-
-    switch (changeType) {
-      case ADDED:
-      case MODIFIED:
-        loadPublished(byKey, aic, newName);
-        break;
-
-      case DELETED:
-        loadPublished(byKey, aic, newName);
-        break;
-
-      case COPIED:
-      case RENAMED:
+        String name = fileName;
         if (psa != null) {
-          loadPublished(byKey, aic, oldName);
-        }
-        loadPublished(byKey, aic, newName);
-        break;
+          switch (changeType) {
+            case COPIED:
+            case RENAMED:
+              if (ps.getId().equals(psa)) {
+                name = oldName;
+              }
+              break;
 
-      case REWRITE:
-        break;
+            case MODIFIED:
+            case DELETED:
+            case ADDED:
+            case REWRITE:
+              break;
+          }
+        }
+
+        final Patch p = new Patch(new Patch.Key(ps.getId(), name));
+        history.add(p);
+        byKey.put(p.getKey(), p);
+      }
     }
 
-    final CurrentUser user = control.getCurrentUser();
-    if (user.isIdentifiedUser()) {
-      final Account.Id me = ((IdentifiedUser) user).getAccountId();
+    if (loadComments) {
+      final AccountInfoCacheFactory aic = aicFactory.create();
+      comments = new CommentDetail(psa, psb);
       switch (changeType) {
         case ADDED:
         case MODIFIED:
-          loadDrafts(byKey, aic, me, newName);
+          loadPublished(byKey, aic, newName);
           break;
 
         case DELETED:
-          loadDrafts(byKey, aic, me, newName);
+          loadPublished(byKey, aic, newName);
           break;
 
         case COPIED:
         case RENAMED:
           if (psa != null) {
-            loadDrafts(byKey, aic, me, oldName);
+            loadPublished(byKey, aic, oldName);
           }
-          loadDrafts(byKey, aic, me, newName);
+          loadPublished(byKey, aic, newName);
           break;
 
         case REWRITE:
           break;
       }
-    }
 
-    comments.setAccountInfoCache(aic.create());
+      final CurrentUser user = control.getCurrentUser();
+      if (user.isIdentifiedUser()) {
+        final Account.Id me = ((IdentifiedUser) user).getAccountId();
+        switch (changeType) {
+          case ADDED:
+          case MODIFIED:
+            loadDrafts(byKey, aic, me, newName);
+            break;
+
+          case DELETED:
+            loadDrafts(byKey, aic, me, newName);
+            break;
+
+          case COPIED:
+          case RENAMED:
+            if (psa != null) {
+              loadDrafts(byKey, aic, me, oldName);
+            }
+            loadDrafts(byKey, aic, me, newName);
+            break;
+
+          case REWRITE:
+            break;
+        }
+      }
+
+      comments.setAccountInfoCache(aic.create());
+    }
   }
 
   private void loadPublished(final Map<Patch.Key, Patch> byKey,
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchSetInfoFactory.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchSetInfoFactory.java
index 8165bf2..340300a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchSetInfoFactory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchSetInfoFactory.java
@@ -123,8 +123,7 @@
 
   private List<PatchSetInfo.ParentInfo> toParentInfos(final RevCommit[] parents,
       final RevWalk walk) throws IOException, MissingObjectException {
-    List<PatchSetInfo.ParentInfo> pInfos =
-      new ArrayList<PatchSetInfo.ParentInfo>(parents.length);
+    List<PatchSetInfo.ParentInfo> pInfos = new ArrayList<>(parents.length);
     for (RevCommit parent : parents) {
       walk.parseBody(parent);
       RevId rev = new RevId(parent.getId().name());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginGuiceEnvironment.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginGuiceEnvironment.java
index bc622ad..ba90bdd 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginGuiceEnvironment.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginGuiceEnvironment.java
@@ -108,10 +108,10 @@
     this.copyConfigModule = ccm;
     this.copyConfigKeys = Guice.createInjector(ccm).getAllBindings().keySet();
 
-    onStart = new CopyOnWriteArrayList<StartPluginListener>();
+    onStart = new CopyOnWriteArrayList<>();
     onStart.addAll(listeners(sysInjector, StartPluginListener.class));
 
-    onReload = new CopyOnWriteArrayList<ReloadPluginListener>();
+    onReload = new CopyOnWriteArrayList<>();
     onReload.addAll(listeners(sysInjector, ReloadPluginListener.class));
 
     sysItems = dynamicItemsOf(sysInjector);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginLoader.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginLoader.java
index b4d8df1..a8a0d63 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginLoader.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginLoader.java
@@ -151,7 +151,7 @@
     if (!all) {
       return running.values();
     } else {
-      ArrayList<Plugin> plugins = new ArrayList<Plugin>(running.values());
+      List<Plugin> plugins = new ArrayList<>(running.values());
       plugins.addAll(disabled.values());
       return plugins;
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java
index a2d553e..1ef5378 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java
@@ -29,7 +29,6 @@
 import com.google.gerrit.reviewdb.client.PatchSetApproval;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gerrit.server.ApprovalsUtil;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.notedb.ChangeNotes;
@@ -189,29 +188,25 @@
     }
   }
 
-  private final ApprovalsUtil approvalsUtil;
   private final ChangeData.Factory changeDataFactory;
   private final RefControl refControl;
   private final ChangeNotes notes;
 
   @AssistedInject
   ChangeControl(
-      ApprovalsUtil approvalsUtil,
       ChangeData.Factory changeDataFactory,
       ChangeNotes.Factory notesFactory,
       @Assisted RefControl refControl,
       @Assisted Change change) {
-    this(approvalsUtil, changeDataFactory, refControl,
+    this(changeDataFactory, refControl,
         notesFactory.create(change));
   }
 
   @AssistedInject
   ChangeControl(
-      ApprovalsUtil approvalsUtil,
       ChangeData.Factory changeDataFactory,
       @Assisted RefControl refControl,
       @Assisted ChangeNotes notes) {
-    this.approvalsUtil = approvalsUtil;
     this.changeDataFactory = changeDataFactory;
     this.refControl = refControl;
     this.notes = notes;
@@ -221,7 +216,7 @@
     if (getCurrentUser().equals(who)) {
       return this;
     }
-    return new ChangeControl(approvalsUtil, changeDataFactory,
+    return new ChangeControl(changeDataFactory,
         getRefControl().forUser(who), notes);
   }
 
@@ -510,7 +505,7 @@
    * the out collection is reversed to restore it to the original ordering.
    */
   public List<SubmitRecord> resultsToSubmitRecord(Term submitRule, List<Term> results) {
-    List<SubmitRecord> out = new ArrayList<SubmitRecord>(results.size());
+    List<SubmitRecord> out = new ArrayList<>(results.size());
     for (int resultIdx = results.size() - 1; 0 <= resultIdx; resultIdx--) {
       Term submitRecord = results.get(resultIdx);
       SubmitRecord rec = new SubmitRecord();
@@ -539,7 +534,7 @@
         return logInvalidResult(submitRule, submitRecord);
       }
 
-      rec.labels = new ArrayList<SubmitRecord.Label> (submitRecord.arity());
+      rec.labels = new ArrayList<>(submitRecord.arity());
 
       for (Term state : ((StructureTerm) submitRecord).args()) {
         if (!state.isStructure() || 2 != state.arity() || !"label".equals(state.name())) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java
index 8e8c844..3dcf9f4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java
@@ -32,6 +32,7 @@
 import com.google.gerrit.server.project.ListBranches.BranchInfo;
 import com.google.gerrit.server.util.MagicBranch;
 import com.google.inject.Inject;
+import com.google.inject.Provider;
 import com.google.inject.assistedinject.Assisted;
 
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
@@ -64,14 +65,15 @@
     CreateBranch create(String ref);
   }
 
-  private final IdentifiedUser identifiedUser;
+  private final Provider<IdentifiedUser>  identifiedUser;
   private final GitRepositoryManager repoManager;
   private final GitReferenceUpdated referenceUpdated;
   private final ChangeHooks hooks;
   private String ref;
 
   @Inject
-  CreateBranch(IdentifiedUser identifiedUser, GitRepositoryManager repoManager,
+  CreateBranch(Provider<IdentifiedUser> identifiedUser,
+      GitRepositoryManager repoManager,
       GitReferenceUpdated referenceUpdated, ChangeHooks hooks,
       @Assisted String ref) {
     this.identifiedUser = identifiedUser;
@@ -135,7 +137,7 @@
         final RefUpdate u = repo.updateRef(ref);
         u.setExpectedOldObjectId(ObjectId.zeroId());
         u.setNewObjectId(object.copy());
-        u.setRefLogIdent(identifiedUser.newRefLogIdent());
+        u.setRefLogIdent(identifiedUser.get().newRefLogIdent());
         u.setRefLogMessage("created via REST from " + input.revision, false);
         final RefUpdate.Result result = u.update(rw);
         switch (result) {
@@ -143,7 +145,7 @@
           case NEW:
           case NO_CHANGE:
             referenceUpdated.fire(name.getParentKey(), u);
-            hooks.doRefUpdatedHook(name, u, identifiedUser.getAccount());
+            hooks.doRefUpdatedHook(name, u, identifiedUser.get().getAccount());
             break;
           case LOCK_FAILURE:
             if (repo.getRef(ref) != null) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranch.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranch.java
index 600f65d..87e233f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranch.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranch.java
@@ -41,16 +41,16 @@
   static class Input {
   }
 
-  private final IdentifiedUser identifiedUser;
+  private final Provider<IdentifiedUser> identifiedUser;
   private final GitRepositoryManager repoManager;
   private final Provider<ReviewDb> dbProvider;
   private final GitReferenceUpdated referenceUpdated;
   private final ChangeHooks hooks;
 
   @Inject
-  DeleteBranch(IdentifiedUser identifiedUser, GitRepositoryManager repoManager,
-      Provider<ReviewDb> dbProvider, GitReferenceUpdated referenceUpdated,
-      ChangeHooks hooks) {
+  DeleteBranch(Provider<IdentifiedUser> identifiedUser,
+      GitRepositoryManager repoManager, Provider<ReviewDb> dbProvider,
+      GitReferenceUpdated referenceUpdated, ChangeHooks hooks) {
     this.identifiedUser = identifiedUser;
     this.repoManager = repoManager;
     this.dbProvider = dbProvider;
@@ -89,7 +89,7 @@
         case FAST_FORWARD:
         case FORCED:
           referenceUpdated.fire(rsrc.getNameKey(), u);
-          hooks.doRefUpdatedHook(rsrc.getBranchKey(), u, identifiedUser.getAccount());
+          hooks.doRefUpdatedHook(rsrc.getBranchKey(), u, identifiedUser.get().getAccount());
           break;
 
         case REJECTED_CURRENT_BRANCH:
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java
index 55f15f5..5153c06 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java
@@ -247,10 +247,9 @@
     int found = 0;
     Map<String, ProjectInfo> output = Maps.newTreeMap();
     Map<String, String> hiddenNames = Maps.newHashMap();
-    Set<String> rejected = new HashSet<String>();
+    Set<String> rejected = new HashSet<>();
 
-    final TreeMap<Project.NameKey, ProjectNode> treeMap =
-        new TreeMap<Project.NameKey, ProjectNode>();
+    final TreeMap<Project.NameKey, ProjectNode> treeMap = new TreeMap<>();
     try {
       for (final Project.NameKey projectName : scan()) {
         final ProjectState e = projectCache.get(projectName);
@@ -455,7 +454,7 @@
 
   private void printProjectTree(final PrintWriter stdout,
       final TreeMap<Project.NameKey, ProjectNode> treeMap) {
-    final SortedSet<ProjectNode> sortedNodes = new TreeSet<ProjectNode>();
+    final SortedSet<ProjectNode> sortedNodes = new TreeSet<>();
 
     // Builds the inheritance tree using a list.
     //
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/PerRequestProjectControlCache.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/PerRequestProjectControlCache.java
index 19a42ae..f46a881 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/PerRequestProjectControlCache.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/PerRequestProjectControlCache.java
@@ -34,7 +34,7 @@
       CurrentUser userProvider) {
     this.projectCache = projectCache;
     this.user = userProvider;
-    this.controls = new HashMap<Project.NameKey, ProjectControl>();
+    this.controls = new HashMap<>();
   }
 
   ProjectControl get(Project.NameKey nameKey) throws NoSuchProjectException {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/PerformCreateProject.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/PerformCreateProject.java
index 22a761b..f8cd9c1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/PerformCreateProject.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/PerformCreateProject.java
@@ -240,11 +240,10 @@
 
     if (createProjectArgs.ownerIds == null
         || createProjectArgs.ownerIds.isEmpty()) {
-      createProjectArgs.ownerIds =
-          new ArrayList<AccountGroup.UUID>(projectOwnerGroups);
+      createProjectArgs.ownerIds = new ArrayList<>(projectOwnerGroups);
     }
 
-    List<String> transformedBranches = new ArrayList<String>();
+    List<String> transformedBranches = new ArrayList<>();
     if (createProjectArgs.branch == null ||
         createProjectArgs.branch.isEmpty()) {
       createProjectArgs.branch = Collections.singletonList(Constants.MASTER);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/PermissionCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/PermissionCollection.java
index 3b6ce91..f3ad45f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/PermissionCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/PermissionCollection.java
@@ -109,12 +109,11 @@
       List<AccessSection> sections = Lists.newArrayList(sectionToProject.keySet());
       sorter.sort(ref, sections);
 
-      Set<SeenRule> seen = new HashSet<SeenRule>();
-      Set<SeenRule> seenBlockingRules = new HashSet<SeenRule>();
-      Set<String> exclusiveGroupPermissions = new HashSet<String>();
+      Set<SeenRule> seen = new HashSet<>();
+      Set<SeenRule> seenBlockingRules = new HashSet<>();
+      Set<String> exclusiveGroupPermissions = new HashSet<>();
 
-      HashMap<String, List<PermissionRule>> permissions =
-          new HashMap<String, List<PermissionRule>>();
+      HashMap<String, List<PermissionRule>> permissions = new HashMap<>();
       Map<PermissionRule, ProjectRef> ruleProps = Maps.newIdentityHashMap();
       for (AccessSection section : sections) {
         Project.NameKey project = sectionToProject.get(section);
@@ -133,7 +132,7 @@
             if (addRule) {
               List<PermissionRule> r = permissions.get(permission.getName());
               if (r == null) {
-                r = new ArrayList<PermissionRule>(2);
+                r = new ArrayList<>(2);
                 permissions.put(permission.getName(), r);
               }
               r.add(rule);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java
index c7cc9c3..53b7368 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java
@@ -193,7 +193,7 @@
 
   public RefControl controlForRef(String refName) {
     if (refControls == null) {
-      refControls = new HashMap<String, RefControl>();
+      refControls = new HashMap<>();
     }
     RefControl ctl = refControls.get(refName);
     if (ctl == null) {
@@ -313,7 +313,7 @@
 
   private static Set<GroupReference> getGroups(
       final List<SectionMatcher> sectionMatcherList) {
-    final Set<GroupReference> all = new HashSet<GroupReference>();
+    final Set<GroupReference> all = new HashSet<>();
     for (final SectionMatcher matcher : sectionMatcherList) {
       final AccessSection section = matcher.section;
       for (final Permission permission : section.getPermissions()) {
@@ -448,7 +448,7 @@
   }
 
   private Set<String> allRefPatterns(String permissionName) {
-    Set<String> all = new HashSet<String>();
+    Set<String> all = new HashSet<>();
     for (SectionMatcher matcher : access()) {
       AccessSection section = matcher.section;
       Permission permission = section.getPermission(permissionName);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectNode.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectNode.java
index cc85312..e74511a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectNode.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectNode.java
@@ -33,7 +33,7 @@
   private final Project project;
   private final boolean isVisible;
 
-  private final SortedSet<ProjectNode> children = new TreeSet<ProjectNode>();
+  private final SortedSet<ProjectNode> children = new TreeSet<>();
 
   @Inject
   protected ProjectNode(final AllProjectsName allProjectsName,
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
index 88f4d1f..f6b96d7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
@@ -87,7 +87,7 @@
   private final List<CommentLinkInfo> commentLinks;
 
   private final ProjectConfig config;
-  private final Map<ConfigKey, ProjectLevelConfig> configs;
+  private final Map<String, ProjectLevelConfig> configs;
   private final Set<AccountGroup.UUID> localOwners;
 
   /** Prolog rule state. */
@@ -134,7 +134,7 @@
     if (isAllProjects && !Permission.canBeOnAllProjects(AccessSection.ALL, Permission.OWNER)) {
       localOwners = Collections.emptySet();
     } else {
-      HashSet<AccountGroup.UUID> groups = new HashSet<AccountGroup.UUID>();
+      HashSet<AccountGroup.UUID> groups = new HashSet<>();
       AccessSection all = config.getAccessSection(AccessSection.ALL);
       if (all != null) {
         Permission owner = all.getPermission(Permission.OWNER);
@@ -223,16 +223,11 @@
   }
 
   public ProjectLevelConfig getConfig(String fileName) {
-    return getConfig(fileName, RefNames.REFS_CONFIG);
-  }
-
-  public ProjectLevelConfig getConfig(String fileName, String ref) {
-    ConfigKey cfgKey = new ConfigKey(fileName, ref);
-    if (configs.containsKey(cfgKey)) {
-      return configs.get(cfgKey);
+    if (configs.containsKey(fileName)) {
+      return configs.get(fileName);
     }
 
-    ProjectLevelConfig cfg = new ProjectLevelConfig(fileName, ref, this);
+    ProjectLevelConfig cfg = new ProjectLevelConfig(fileName, this);
     try {
       Repository git = gitMgr.openRepository(getProject().getNameKey());
       try {
@@ -246,7 +241,7 @@
       log.warn("Failed to load " + fileName + " for " + getProject().getName(), e);
     }
 
-    configs.put(cfgKey, cfg);
+    configs.put(fileName, cfg);
     return cfg;
   }
 
@@ -259,7 +254,7 @@
     List<SectionMatcher> sm = localAccessSections;
     if (sm == null) {
       Collection<AccessSection> fromConfig = config.getAccessSections();
-      sm = new ArrayList<SectionMatcher>(fromConfig.size());
+      sm = new ArrayList<>(fromConfig.size());
       for (AccessSection section : fromConfig) {
         if (isAllProjects) {
           List<Permission> copy =
@@ -505,26 +500,4 @@
     }
     return false;
   }
-
-  private static class ConfigKey {
-    final String file;
-    final String ref;
-
-    ConfigKey(String file, String ref) {
-      this.file = file;
-      this.ref = ref;
-    }
-
-    @Override
-    public boolean equals(Object other) {
-      return other instanceof ConfigKey
-          && file.equals(((ConfigKey) other).file)
-          && ref.equals(((ConfigKey) other).ref);
-    }
-
-    @Override
-    public int hashCode() {
-      return file.hashCode() * 31 + ref.hashCode();
-    }
-  }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
index da093b6..00ecee3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
@@ -68,7 +68,7 @@
     this.projectControl = projectControl;
     this.refName = ref;
     this.relevant = relevant;
-    this.effective = new HashMap<String, List<PermissionRule>>();
+    this.effective = new HashMap<>();
   }
 
   public String getRefName() {
@@ -387,7 +387,7 @@
 
   /** All value ranges of any allowed label permission. */
   public List<PermissionRange> getLabelRanges(boolean isChangeOwner) {
-    List<PermissionRange> r = new ArrayList<PermissionRange>();
+    List<PermissionRange> r = new ArrayList<>();
     for (Map.Entry<String, List<PermissionRule>> e : relevant.getDeclaredPermissions()) {
       if (Permission.isLabel(e.getKey())) {
         int min = 0;
@@ -565,7 +565,7 @@
       return rules;
     }
 
-    List<PermissionRule> mine = new ArrayList<PermissionRule>(rules.size());
+    List<PermissionRule> mine = new ArrayList<>(rules.size());
     for (PermissionRule rule : rules) {
       if (projectControl.match(rule, isChangeOwner)) {
         mine.add(rule);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/SectionSortCache.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/SectionSortCache.java
index aeb92d3..c012bd5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/SectionSortCache.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/SectionSortCache.java
@@ -77,8 +77,7 @@
 
     } else {
       boolean poison = false;
-      IdentityHashMap<AccessSection, Integer> srcMap =
-          new IdentityHashMap<AccessSection, Integer>();
+      IdentityHashMap<AccessSection, Integer> srcMap = new IdentityHashMap<>();
       for (int i = 0; i < cnt; i++) {
         poison |= srcMap.put(sections.get(i), i) != null;
       }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
index f7c3c9d..d79716c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
@@ -134,7 +134,7 @@
         env.once("gerrit", "assume_range_from_label");
       }
 
-      List<Term> results = new ArrayList<Term>();
+      List<Term> results = new ArrayList<>();
       try {
         for (Term[] template : env.all("gerrit", userRuleWrapperName,
             submitRule, new VariableTerm())) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/SuggestParentCandidates.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/SuggestParentCandidates.java
index c73de60..4a4e82d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/SuggestParentCandidates.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/SuggestParentCandidates.java
@@ -45,8 +45,7 @@
   public List<Project.NameKey> getNameKeys() throws OrmException,
       NoSuchProjectException {
     List<Project> pList = getProjects();
-    final List<Project.NameKey> nameKeys =
-        new ArrayList<Project.NameKey>(pList.size());
+    final List<Project.NameKey> nameKeys = new ArrayList<>(pList.size());
     for (Project p : pList) {
       nameKeys.add(p.getNameKey());
     }
@@ -55,7 +54,7 @@
 
   public List<Project> getProjects() throws OrmException,
       NoSuchProjectException {
-    Set<Project> projects = new TreeSet<Project>(new Comparator<Project>() {
+    Set<Project> projects = new TreeSet<>(new Comparator<Project>() {
       @Override
       public int compare(Project o1, Project o2) {
         return o1.getName().compareTo(o2.getName());
@@ -76,6 +75,6 @@
       }
     }
     projects.add(projectControlFactory.controlFor(allProject).getProject());
-    return new ArrayList<Project>(projects);
+    return new ArrayList<>(projects);
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/AndPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/AndPredicate.java
index 915a364..953dabf 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/AndPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/AndPredicate.java
@@ -33,7 +33,7 @@
   }
 
   protected AndPredicate(final Collection<? extends Predicate<T>> that) {
-    final ArrayList<Predicate<T>> t = new ArrayList<Predicate<T>>(that.size());
+    List<Predicate<T>> t = new ArrayList<>(that.size());
     int c = 0;
     for (Predicate<T> p : that) {
       if (getClass() == p.getClass()) {
@@ -67,7 +67,7 @@
 
   @Override
   public Predicate<T> copy(final Collection<? extends Predicate<T>> children) {
-    return new AndPredicate<T>(children);
+    return new AndPredicate<>(children);
   }
 
   @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/NotPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/NotPredicate.java
index f94e1f6..6a9a877 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/NotPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/NotPredicate.java
@@ -54,7 +54,7 @@
     if (children.size() != 1) {
       throw new IllegalArgumentException("Expected exactly one child");
     }
-    return new NotPredicate<T>(children.iterator().next());
+    return new NotPredicate<>(children.iterator().next());
   }
 
   @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/OrPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/OrPredicate.java
index 2c91809..845c805 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/OrPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/OrPredicate.java
@@ -33,7 +33,7 @@
   }
 
   protected OrPredicate(final Collection<? extends Predicate<T>> that) {
-    final ArrayList<Predicate<T>> t = new ArrayList<Predicate<T>>(that.size());
+    List<Predicate<T>> t = new ArrayList<>(that.size());
     int c = 0;
     for (Predicate<T> p : that) {
       if (getClass() == p.getClass()) {
@@ -67,7 +67,7 @@
 
   @Override
   public Predicate<T> copy(final Collection<? extends Predicate<T>> children) {
-    return new OrPredicate<T>(children);
+    return new OrPredicate<>(children);
   }
 
   @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/Predicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/Predicate.java
index c134458..7b43572 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/Predicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/Predicate.java
@@ -55,7 +55,7 @@
     if (that.length == 1) {
       return that[0];
     }
-    return new AndPredicate<T>(that);
+    return new AndPredicate<>(that);
   }
 
   /** Combine the passed predicates into a single AND node. */
@@ -64,7 +64,7 @@
     if (that.size() == 1) {
       return Iterables.getOnlyElement(that);
     }
-    return new AndPredicate<T>(that);
+    return new AndPredicate<>(that);
   }
 
   /** Combine the passed predicates into a single OR node. */
@@ -73,7 +73,7 @@
     if (that.length == 1) {
       return that[0];
     }
-    return new OrPredicate<T>(that);
+    return new OrPredicate<>(that);
   }
 
   /** Combine the passed predicates into a single OR node. */
@@ -82,7 +82,7 @@
     if (that.size() == 1) {
       return Iterables.getOnlyElement(that);
     }
-    return new OrPredicate<T>(that);
+    return new OrPredicate<>(that);
   }
 
   /** Invert the passed node. */
@@ -130,7 +130,7 @@
   public abstract boolean equals(Object other);
 
   private static class Any<T> extends Predicate<T> {
-    private static final Any<Object> INSTANCE = new Any<Object>();
+    private static final Any<Object> INSTANCE = new Any<>();
 
     private Any() {
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/QueryBuilder.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/QueryBuilder.java
index a276992..5be42be 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/QueryBuilder.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/QueryBuilder.java
@@ -84,7 +84,7 @@
    */
   public static class Definition<T, Q extends QueryBuilder<T>> {
     private final Map<String, OperatorFactory<T, Q>> opFactories =
-        new HashMap<String, OperatorFactory<T, Q>>();
+        new HashMap<>();
 
     public Definition(Class<Q> clazz) {
       // Guess at the supported operators by scanning methods.
@@ -204,11 +204,11 @@
           final Tree val = onlyChildOf(opTree);
           if (val.getType() == SINGLE_WORD && "*".equals(val.getText())) {
             final String op = opTree.getText();
-            final WildPatternPredicate<T> pat = new WildPatternPredicate<T>(op);
-            return new VariablePredicate<T>(var, pat);
+            final WildPatternPredicate<T> pat = new WildPatternPredicate<>(op);
+            return new VariablePredicate<>(var, pat);
           }
         }
-        return new VariablePredicate<T>(var, toPredicate(opTree));
+        return new VariablePredicate<>(var, toPredicate(opTree));
       }
 
       default:
@@ -224,7 +224,7 @@
       //
       case AND:
       case OR: {
-        List<Predicate<T>> p = new ArrayList<Predicate<T>>(val.getChildCount());
+        List<Predicate<T>> p = new ArrayList<>(val.getChildCount());
         for (int i = 0; i < val.getChildCount(); i++) {
           final Tree c = val.getChild(i);
           if (c.getType() != DEFAULT_FIELD) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/QueryRewriter.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/QueryRewriter.java
index c0f8414..6173fb6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/QueryRewriter.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/QueryRewriter.java
@@ -76,7 +76,7 @@
           if ((m.getModifiers() & Modifier.ABSTRACT) != Modifier.ABSTRACT
               && (m.getModifiers() & Modifier.PUBLIC) == Modifier.PUBLIC
               && rp != null) {
-            rewriteRules.add(new MethodRewrite<T>(qb, rp.value(), m));
+            rewriteRules.add(new MethodRewrite<>(qb, rp.value(), m));
           }
         }
         c = c.getSuperclass();
@@ -138,7 +138,7 @@
       in = rewriteOne(in);
 
       if (old.equals(in) && in.getChildCount() > 0) {
-        List<Predicate<T>> n = new ArrayList<Predicate<T>>(in.getChildCount());
+        List<Predicate<T>> n = new ArrayList<>(in.getChildCount());
         for (Predicate<T> p : in.getChildren()) {
           n.add(rewriteImpl(p));
         }
@@ -159,14 +159,14 @@
       return not(replaceGenericNodes(in.getChild(0)));
 
     } else if (in instanceof AndPredicate) {
-      List<Predicate<T>> n = new ArrayList<Predicate<T>>(in.getChildCount());
+      List<Predicate<T>> n = new ArrayList<>(in.getChildCount());
       for (Predicate<T> c : in.getChildren()) {
         n.add(replaceGenericNodes(c));
       }
       return and(n);
 
     } else if (in instanceof OrPredicate) {
-      List<Predicate<T>> n = new ArrayList<Predicate<T>>(in.getChildCount());
+      List<Predicate<T>> n = new ArrayList<>(in.getChildCount());
       for (Predicate<T> c : in.getChildren()) {
         n.add(replaceGenericNodes(c));
       }
@@ -198,8 +198,8 @@
   }
 
   private static class MatchResult<T> {
-    private static final MatchResult<?> FAIL = new MatchResult<Object>(null);
-    private static final MatchResult<?> OK = new MatchResult<Object>(null);
+    private static final MatchResult<?> FAIL = new MatchResult<>(null);
+    private static final MatchResult<?> OK = new MatchResult<>(null);
 
     @SuppressWarnings("unchecked")
     static <T> MatchResult<T> fail() {
@@ -251,7 +251,7 @@
       // but in any order.
       //
       final LinkedList<Predicate<T>> have = dup(actual);
-      final LinkedList<Predicate<T>> extra = new LinkedList<Predicate<T>>();
+      final LinkedList<Predicate<T>> extra = new LinkedList<>();
       for (final Predicate<T> pat : pattern.getChildren()) {
         boolean found = false;
         for (final Iterator<Predicate<T>> i = have.iterator(); i.hasNext();) {
@@ -275,11 +275,11 @@
           return MatchResult.ok();
         case 1:
           if (isNOT(actual)) {
-            return new MatchResult<T>(actual.copy(have));
+            return new MatchResult<>(actual.copy(have));
           }
-          return new MatchResult<T>(have.get(0));
+          return new MatchResult<>(have.get(0));
         default:
-          return new MatchResult<T>(actual.copy(have));
+          return new MatchResult<>(actual.copy(have));
       }
 
     } else if (pattern.equals(actual)) {
@@ -297,7 +297,7 @@
   }
 
   private static <T> LinkedList<Predicate<T>> dup(final Predicate<T> actual) {
-    return new LinkedList<Predicate<T>>(actual.getChildren());
+    return new LinkedList<>(actual.getChildren());
   }
 
   /**
@@ -412,8 +412,7 @@
     @Override
     public Predicate<T> rewrite(QueryRewriter<T> rewriter,
         final Predicate<T> input) {
-      final HashMap<String, Predicate<T>> args =
-          new HashMap<String, Predicate<T>>();
+      final HashMap<String, Predicate<T>> args = new HashMap<>();
       final MatchResult<T> res = rewriter.match(args, pattern, input);
       if (!res.success()) {
         return null;
@@ -483,7 +482,7 @@
   }
 
   private static <T> List<Predicate<T>> removeDuplicates(List<Predicate<T>> n) {
-    List<Predicate<T>> r = new ArrayList<Predicate<T>>();
+    List<Predicate<T>> r = new ArrayList<>();
     for (Predicate<T> p : n) {
       if (!r.contains(p)) {
         r.add(p);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/VariablePredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/VariablePredicate.java
index 45b27e5..d6d0f9c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/VariablePredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/VariablePredicate.java
@@ -61,7 +61,7 @@
     if (children.size() != 1) {
       throw new IllegalArgumentException("Expected exactly one child");
     }
-    return new VariablePredicate<T>(getName(), children.iterator().next());
+    return new VariablePredicate<>(getName(), children.iterator().next());
   }
 
   @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AbstractResultSet.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AbstractResultSet.java
index e072760..9bbc02f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AbstractResultSet.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AbstractResultSet.java
@@ -22,7 +22,7 @@
 abstract class AbstractResultSet<T> implements ResultSet<T> {
   @Override
   public List<T> toList() {
-    ArrayList<T> r = new ArrayList<T>();
+    ArrayList<T> r = new ArrayList<>();
     for (T t : this) {
       r.add(t);
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AndSource.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AndSource.java
index ad0ec3c..55fd281 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AndSource.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AndSource.java
@@ -68,8 +68,7 @@
 
   private static List<Predicate<ChangeData>> sort(
       Collection<? extends Predicate<ChangeData>> that) {
-    ArrayList<Predicate<ChangeData>> r =
-        new ArrayList<Predicate<ChangeData>>(that);
+    List<Predicate<ChangeData>> r = new ArrayList<>(that);
     Collections.sort(r, CMP);
     return r;
   }
@@ -158,7 +157,7 @@
     } else if (start > 0) {
       r = ImmutableList.copyOf(r.subList(start, r.size()));
     }
-    return new ListResultSet<ChangeData>(r);
+    return new ListResultSet<>(r);
   }
 
   private Iterable<ChangeData> buffer(
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
index 333c343..3d7c779 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
@@ -281,7 +281,7 @@
         return currentFiles;
       }
 
-      List<String> r = new ArrayList<String>(p.getPatches().size());
+      List<String> r = new ArrayList<>(p.getPatches().size());
       for (PatchListEntry e : p.getPatches()) {
         if (Patch.COMMIT_MSG.equals(e.getNewName())) {
           continue;
@@ -343,12 +343,15 @@
     return changeControl != null;
   }
 
-  public ChangeControl changeControl() throws NoSuchChangeException,
-      OrmException {
+  public ChangeControl changeControl() throws OrmException {
     if (changeControl == null) {
       Change c = change();
-      changeControl =
-          changeControlFactory.controlFor(c, userFactory.create(c.getOwner()));
+      try {
+        changeControl =
+            changeControlFactory.controlFor(c, userFactory.create(c.getOwner()));
+      } catch (NoSuchChangeException e) {
+        throw new OrmException(e);
+      }
     }
     return changeControl;
   }
@@ -394,11 +397,9 @@
       Change c = change();
       if (c == null) {
         currentApprovals = Collections.emptyList();
-      } else if (allApprovals != null) {
-        return allApprovals.get(c.currentPatchSetId());
       } else {
-        currentApprovals = approvalsUtil.byPatchSet(
-            db, notes(), c.currentPatchSetId());
+        currentApprovals = ImmutableList.copyOf(approvalsUtil.byPatchSet(
+            db, changeControl(), c.currentPatchSetId()));
       }
     }
     return currentApprovals;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeDataResultSet.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeDataResultSet.java
index f469228..52a5b7b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeDataResultSet.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeDataResultSet.java
@@ -23,6 +23,7 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
+import java.util.Set;
 
 abstract class ChangeDataResultSet<T> extends AbstractResultSet<ChangeData> {
   static ResultSet<ChangeData> change(final ChangeData.Factory factory,
@@ -78,7 +79,7 @@
     } else {
       return new Iterator<ChangeData>() {
         private final Iterator<T> itr = source.iterator();
-        private final HashSet<Change.Id> seen = new HashSet<Change.Id>();
+        private final Set<Change.Id> seen = new HashSet<>();
         private ChangeData next;
 
         @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
index 8ffd88a..4c595ea 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
@@ -269,7 +269,7 @@
 
   @Operator
   public Predicate<ChangeData> status(String statusName) {
-    if ("open".equals(statusName)) {
+    if ("open".equals(statusName) || "pending".equals(statusName)) {
       return status_open();
 
     } else if ("closed".equals(statusName)) {
@@ -548,7 +548,7 @@
     //
     Collection<GroupReference> suggestions = args.groupBackend.suggest(who, null);
     if (!suggestions.isEmpty()) {
-      HashSet<AccountGroup.UUID> ids = new HashSet<AccountGroup.UUID>();
+      HashSet<AccountGroup.UUID> ids = new HashSet<>();
       for (GroupReference ref : suggestions) {
         ids.add(ref.getUUID());
       }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeStatusPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeStatusPredicate.java
index 9ff416f..cea6af8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeStatusPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeStatusPredicate.java
@@ -49,7 +49,7 @@
   }
 
   public static Predicate<ChangeData> open(Provider<ReviewDb> dbProvider) {
-    List<Predicate<ChangeData>> r = new ArrayList<Predicate<ChangeData>>(4);
+    List<Predicate<ChangeData>> r = new ArrayList<>(4);
     for (final Change.Status e : Change.Status.values()) {
       if (e.isOpen()) {
         r.add(new ChangeStatusPredicate(e));
@@ -59,7 +59,7 @@
   }
 
   public static Predicate<ChangeData> closed(Provider<ReviewDb> dbProvider) {
-    List<Predicate<ChangeData>> r = new ArrayList<Predicate<ChangeData>>(4);
+    List<Predicate<ChangeData>> r = new ArrayList<>(4);
     for (final Change.Status e : Change.Status.values()) {
       if (e.isClosed()) {
         r.add(new ChangeStatusPredicate(e));
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsLabelPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsLabelPredicate.java
index 54e5a7d..db9b29d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsLabelPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsLabelPredicate.java
@@ -63,13 +63,19 @@
       //
       return false;
     }
+
     ProjectState project = projectCache.get(c.getDest().getParentKey());
     if (project == null) {
       // The project has disappeared.
       //
       return false;
     }
+
     LabelType labelType = type(project.getLabelTypes(), label);
+    if (labelType == null) {
+      return false; // Label is not defined by this project.
+    }
+
     boolean hasVote = false;
     for (PatchSetApproval p : object.currentApprovals()) {
       if (labelType.matches(p)) {
@@ -103,8 +109,7 @@
         return lt;
       }
     }
-
-    return LabelType.withDefaultValues(toFind);
+    return null;
   }
 
   private boolean match(Change change, int value, Account.Id approver,
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasDraftByPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasDraftByPredicate.java
index 6d44b96..53d2bbd 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasDraftByPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasDraftByPredicate.java
@@ -25,6 +25,8 @@
 
 import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
 class HasDraftByPredicate extends OperatorPredicate<ChangeData> implements
     ChangeDataSource {
@@ -50,17 +52,17 @@
 
   @Override
   public ResultSet<ChangeData> read() throws OrmException {
-    HashSet<Change.Id> ids = new HashSet<Change.Id>();
+    Set<Change.Id> ids = new HashSet<>();
     for (PatchLineComment sc : args.db.get().patchComments()
         .draftByAuthor(accountId)) {
       ids.add(sc.getKey().getParentKey().getParentKey().getParentKey());
     }
 
-    ArrayList<ChangeData> r = new ArrayList<ChangeData>(ids.size());
+    List<ChangeData> r = new ArrayList<>(ids.size());
     for (Change.Id id : ids) {
       r.add(args.changeDataFactory.create(args.db.get(), id));
     }
-    return new ListResultSet<ChangeData>(r);
+    return new ListResultSet<>(r);
   }
 
   @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/LegacyChangeIdPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/LegacyChangeIdPredicate.java
index c62d7ca..1cbb499 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/LegacyChangeIdPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/LegacyChangeIdPredicate.java
@@ -44,10 +44,10 @@
   public ResultSet<ChangeData> read() throws OrmException {
     Change c = args.db.get().changes().get(id);
     if (c != null) {
-      return new ListResultSet<ChangeData>(Collections.singletonList(
+      return new ListResultSet<>(Collections.singletonList(
           args.changeDataFactory.create(args.db.get(), c)));
     } else {
-      return new ListResultSet<ChangeData>(Collections.<ChangeData> emptyList());
+      return new ListResultSet<>(Collections.<ChangeData> emptyList());
     }
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OrSource.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OrSource.java
index 4f36777..28aef5e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OrSource.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OrSource.java
@@ -24,6 +24,8 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
 public class OrSource extends OrPredicate<ChangeData> implements ChangeDataSource {
   private int cardinality = -1;
@@ -36,8 +38,8 @@
   public ResultSet<ChangeData> read() throws OrmException {
     // TODO(spearce) This probably should be more lazy.
     //
-    ArrayList<ChangeData> r = new ArrayList<ChangeData>();
-    HashSet<Change.Id> have = new HashSet<Change.Id>();
+    List<ChangeData> r = new ArrayList<>();
+    Set<Change.Id> have = new HashSet<>();
     for (Predicate<ChangeData> p : getChildren()) {
       if (p instanceof ChangeDataSource) {
         for (ChangeData cd : ((ChangeDataSource) p).read()) {
@@ -49,7 +51,7 @@
         throw new OrmException("No ChangeDataSource: " + p);
       }
     }
-    return new ListResultSet<ChangeData>(r);
+    return new ListResultSet<>(r);
   }
 
   @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java
index 3320886..8889f53 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java
@@ -551,7 +551,7 @@
   }
 
   private List<Field> fieldsOf(Class<?> type) {
-    List<Field> r = new ArrayList<Field>();
+    List<Field> r = new ArrayList<>();
     if (type.getSuperclass() != null) {
       r.addAll(fieldsOf(type.getSuperclass()));
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/ReviewDbDatabaseProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/ReviewDbDatabaseProvider.java
index ed77fff..9ceaf1c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/ReviewDbDatabaseProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/ReviewDbDatabaseProvider.java
@@ -36,7 +36,7 @@
   @Override
   public Database<ReviewDb> get() {
     try {
-      return new Database<ReviewDb>(datasource, ReviewDb.class);
+      return new Database<>(datasource, ReviewDb.class);
     } catch (OrmException e) {
       throw new ProvisionException("Cannot create ReviewDb", e);
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_53.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_53.java
index 16ca664..697f303 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_53.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_53.java
@@ -123,7 +123,7 @@
   }
 
   private void assignGroupUUIDs(ReviewDb db) throws OrmException {
-    groupMap = new HashMap<AccountGroup.Id, GroupReference>();
+    groupMap = new HashMap<>();
     List<AccountGroup> groups = db.accountGroups().all().toList();
     for (AccountGroup g : groups) {
       if (g.getId().equals(systemConfig.ownerGroupId)) {
@@ -244,7 +244,7 @@
   }
 
   private void readOldRefRights(ReviewDb db) throws SQLException {
-    rightsByProject = new HashMap<Project.NameKey, List<OldRefRight>>();
+    rightsByProject = new HashMap<>();
 
     Statement stmt = ((JdbcSchema) db).getConnection().createStatement();
     ResultSet rs = stmt.executeQuery("SELECT * FROM ref_rights");
@@ -258,7 +258,7 @@
 
       list = rightsByProject.get(right.project);
       if (list == null) {
-        list = new ArrayList<OldRefRight>();
+        list = new ArrayList<>();
         rightsByProject.put(right.project, list);
       }
       list.add(right);
@@ -268,7 +268,7 @@
   }
 
   private void readProjectParents(ReviewDb db) throws SQLException {
-    parentsByProject = new HashMap<Project.NameKey, Project.NameKey>();
+    parentsByProject = new HashMap<>();
     Statement stmt = ((JdbcSchema) db).getConnection().createStatement();
     ResultSet rs = stmt.executeQuery("SELECT * FROM projects");
     while (rs.next()) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_56.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_56.java
index bcd5f40..852ca2a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_56.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_56.java
@@ -42,8 +42,8 @@
     super(prior);
     this.mgr = mgr;
 
-    keysOne = new HashSet<String>();
-    keysTwo = new HashSet<String>();
+    keysOne = new HashSet<>();
+    keysTwo = new HashSet<>();
 
     keysOne.add(RefNames.REFS_CONFIG);
     keysTwo.add(RefNames.REFS_CONFIG);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_60.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_60.java
index 3f49b0c..7fe0cde 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_60.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_60.java
@@ -40,7 +40,7 @@
     Pattern patternA = Pattern.compile("Patch Set ([0-9]+):.*", Pattern.DOTALL);
     Pattern patternB = Pattern.compile("Uploaded patch set ([0-9]+).");
     ResultSet<ChangeMessage> results = db.changeMessages().all();
-    List<ChangeMessage> updates = new LinkedList<ChangeMessage>();
+    List<ChangeMessage> updates = new LinkedList<>();
     for (ChangeMessage cm : results) {
       Change.Id id = cm.getKey().getParentKey();
       String msg = cm.getMessage();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_74.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_74.java
index 4a2c477..e5480b4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_74.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_74.java
@@ -43,18 +43,15 @@
   protected void migrateData(final ReviewDb db, final UpdateUI ui)
       throws SQLException, OrmException {
     // Grab all the groups since we don't have the cache available
-    HashMap<AccountGroup.Id, AccountGroup.UUID> allGroups =
-        new HashMap<AccountGroup.Id, AccountGroup.UUID>();
+    HashMap<AccountGroup.Id, AccountGroup.UUID> allGroups = new HashMap<>();
     for (AccountGroup ag : db.accountGroups().all()) {
       allGroups.put(ag.getId(), ag.getGroupUUID());
     }
 
     // Initialize some variables
     Connection conn = ((JdbcSchema) db).getConnection();
-    ArrayList<AccountGroupById> newIncludes =
-        new ArrayList<AccountGroupById>();
-    ArrayList<AccountGroupByIdAud> newIncludeAudits =
-        new ArrayList<AccountGroupByIdAud>();
+    ArrayList<AccountGroupById> newIncludes = new ArrayList<>();
+    ArrayList<AccountGroupByIdAud> newIncludeAudits = new ArrayList<>();
 
     // Iterate over all entries in account_group_includes
     Statement oldGroupIncludesStmt = conn.createStatement();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/ScriptRunner.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/ScriptRunner.java
index 12c80f4..d03cb3e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/ScriptRunner.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/ScriptRunner.java
@@ -78,7 +78,7 @@
     BufferedReader br = new BufferedReader(new InputStreamReader(in, "UTF-8"));
     try {
       String delimiter = ";";
-      List<String> commands = new ArrayList<String>();
+      List<String> commands = new ArrayList<>();
       StringBuilder buffer = new StringBuilder();
       String line;
       while ((line = br.readLine()) != null) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/tools/ToolsCatalog.java b/gerrit-server/src/main/java/com/google/gerrit/server/tools/ToolsCatalog.java
index a2b0ad1..3e41858 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/tools/ToolsCatalog.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/tools/ToolsCatalog.java
@@ -69,7 +69,7 @@
   }
 
   private static SortedMap<String, Entry> readToc() throws IOException {
-    SortedMap<String, Entry> toc = new TreeMap<String, Entry>();
+    SortedMap<String, Entry> toc = new TreeMap<>();
     final BufferedReader br =
         new BufferedReader(new InputStreamReader(new ByteArrayInputStream(
             read("TOC")), "UTF-8"));
@@ -81,7 +81,7 @@
       }
     }
 
-    final List<Entry> all = new ArrayList<Entry>(toc.values());
+    final List<Entry> all = new ArrayList<>(toc.values());
     for (Entry e : all) {
       String path = dirOf(e.getPath());
       while (path != null) {
@@ -159,7 +159,7 @@
       if (type == Type.FILE) {
         this.children = Collections.emptyList();
       } else {
-        this.children = new ArrayList<Entry>();
+        this.children = new ArrayList<>();
       }
     }
 
@@ -167,7 +167,7 @@
       this.type = type;
       this.mode = mode;
       this.path = path;
-      this.children = new ArrayList<Entry>();
+      this.children = new ArrayList<>();
     }
 
     public Type getType() {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/util/SubmoduleSectionParser.java b/gerrit-server/src/main/java/com/google/gerrit/server/util/SubmoduleSectionParser.java
index fbb3e93..8970425 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/util/SubmoduleSectionParser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/util/SubmoduleSectionParser.java
@@ -60,8 +60,7 @@
   }
 
   public List<SubmoduleSubscription> parseAllSections() {
-    List<SubmoduleSubscription> parsedSubscriptions =
-        new ArrayList<SubmoduleSubscription>();
+    List<SubmoduleSubscription> parsedSubscriptions = new ArrayList<>();
     for (final String id : bbc.getSubsections("submodule")) {
       final SubmoduleSubscription subscription = parse(id);
       if (subscription != null) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/util/ThreadLocalRequestContext.java b/gerrit-server/src/main/java/com/google/gerrit/server/util/ThreadLocalRequestContext.java
index 2a67c90..f8bad77 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/util/ThreadLocalRequestContext.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/util/ThreadLocalRequestContext.java
@@ -72,8 +72,7 @@
     };
   }
 
-  private static final ThreadLocal<RequestContext> local =
-      new ThreadLocal<RequestContext>();
+  private static final ThreadLocal<RequestContext> local = new ThreadLocal<>();
 
   @Inject
   ThreadLocalRequestContext() {
diff --git a/gerrit-server/src/test/java/com/google/gerrit/rules/PrologTestCase.java b/gerrit-server/src/test/java/com/google/gerrit/rules/PrologTestCase.java
index 19edaf4..c697400 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/rules/PrologTestCase.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/rules/PrologTestCase.java
@@ -57,7 +57,7 @@
 
   protected void load(String pkg, String prologResource, Module... modules)
       throws CompileException, IOException {
-    ArrayList<Module> moduleList = new ArrayList<Module>();
+    ArrayList<Module> moduleList = new ArrayList<>();
     moduleList.add(new PrologModule.EnvironmentModule());
     moduleList.addAll(Arrays.asList(modules));
 
@@ -74,7 +74,7 @@
         SymbolTerm.intern(pkg),
         new StructureTerm(test_1, new VariableTerm()));
 
-    tests = new ArrayList<Term>();
+    tests = new ArrayList<>();
     for (Term[] pair : env.all(Prolog.BUILTIN, "clause", head, new VariableTerm())) {
       tests.add(pair[0]);
     }
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/change/CommentsTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/change/CommentsTest.java
index 6c24f00..8fdad6f 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/change/CommentsTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/change/CommentsTest.java
@@ -158,7 +158,7 @@
     return new IAnswer<ResultSet<PatchLineComment>>() {
       @Override
       public ResultSet<PatchLineComment> answer() throws Throwable {
-        return new ListResultSet<PatchLineComment>(Lists.newArrayList(comments));
+        return new ListResultSet<>(Lists.newArrayList(comments));
       }};
   }
 
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/change/IncludedInResolverTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/change/IncludedInResolverTest.java
index ae58819..65eede6 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/change/IncludedInResolverTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/change/IncludedInResolverTest.java
@@ -58,8 +58,8 @@
   private RevCommit commit_v1_3;
   private RevCommit commit_v2_5;
 
-  private List<String> expTags = new ArrayList<String>();
-  private List<String> expBranches = new ArrayList<String>();
+  private List<String> expTags = new ArrayList<>();
+  private List<String> expBranches = new ArrayList<>();
 
   private RevWalk revWalk;
 
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/git/ProjectConfigTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/git/ProjectConfigTest.java
index 1a9f74b..cc4a9e3 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/git/ProjectConfigTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/git/ProjectConfigTest.java
@@ -21,9 +21,11 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import com.google.common.collect.Iterables;
 import com.google.gerrit.common.data.AccessSection;
 import com.google.gerrit.common.data.ContributorAgreement;
 import com.google.gerrit.common.data.GroupReference;
+import com.google.gerrit.common.data.LabelType;
 import com.google.gerrit.common.data.Permission;
 import com.google.gerrit.common.data.PermissionRule;
 import com.google.gerrit.reviewdb.client.AccountGroup;
@@ -47,6 +49,7 @@
 
 import java.io.IOException;
 import java.util.Collections;
+import java.util.Map;
 
 public class ProjectConfigTest extends LocalDiskRepositoryTestCase {
   private final GroupReference developers = new GroupReference(
@@ -62,7 +65,7 @@
   public void setUp() throws Exception {
     super.setUp();
     db = createBareRepository();
-    util = new TestRepository<Repository>(db);
+    util = new TestRepository<>(db);
   }
 
   @Test
@@ -115,6 +118,60 @@
   }
 
   @Test
+  public void testReadConfigLabelDefaultValue() throws Exception {
+    RevCommit rev = util.commit(util.tree( //
+        util.file("groups", util.blob(group(developers))), //
+        util.file("project.config", util.blob(""//
+            + "[label \"CustomLabel\"]\n" //
+            + "  value = -1 Negative\n" //
+            + "  value =  0 No Score\n" //
+            + "  value =  1 Positive\n")) //
+        ));
+
+    ProjectConfig cfg = read(rev);
+    Map<String, LabelType> labels = cfg.getLabelSections();
+    Short dv = labels.entrySet().iterator().next().getValue().getDefaultValue();
+    assertEquals(0, (int) dv);
+  }
+
+  @Test
+  public void testReadConfigLabelDefaultValueInRange() throws Exception {
+    RevCommit rev = util.commit(util.tree( //
+        util.file("groups", util.blob(group(developers))), //
+        util.file("project.config", util.blob(""//
+            + "[label \"CustomLabel\"]\n" //
+            + "  value = -1 Negative\n" //
+            + "  value =  0 No Score\n" //
+            + "  value =  1 Positive\n" //
+            + "  defaultValue = -1\n")) //
+        ));
+
+    ProjectConfig cfg = read(rev);
+    Map<String, LabelType> labels = cfg.getLabelSections();
+    Short dv = labels.entrySet().iterator().next().getValue().getDefaultValue();
+    assertEquals(-1, (int) dv);
+  }
+
+  @Test
+  public void testReadConfigLabelDefaultValueNotInRange() throws Exception {
+    RevCommit rev = util.commit(util.tree( //
+        util.file("groups", util.blob(group(developers))), //
+        util.file("project.config", util.blob(""//
+            + "[label \"CustomLabel\"]\n" //
+            + "  value = -1 Negative\n" //
+            + "  value =  0 No Score\n" //
+            + "  value =  1 Positive\n" //
+            + "  defaultValue = -2\n")) //
+        ));
+
+    ProjectConfig cfg = read(rev);
+    assertEquals(1, cfg.getValidationErrors().size());
+    assertEquals("project.config: Invalid defaultValue \"-2\" "
+        + "for label \"CustomLabel\"",
+        Iterables.getOnlyElement(cfg.getValidationErrors()).getMessage());
+  }
+
+  @Test
   public void testEditConfig() throws Exception {
     RevCommit rev = util.commit(util.tree( //
         util.file("groups", util.blob(group(developers))), //
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/git/SubmoduleOpTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/git/SubmoduleOpTest.java
index 33ba36e..f931dbf 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/git/SubmoduleOpTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/git/SubmoduleOpTest.java
@@ -127,7 +127,7 @@
 
     expect(schema.submoduleSubscriptions()).andReturn(subscriptions);
     final ResultSet<SubmoduleSubscription> emptySubscriptions =
-        new ListResultSet<SubmoduleSubscription>(new ArrayList<SubmoduleSubscription>());
+        new ListResultSet<>(new ArrayList<SubmoduleSubscription>());
     expect(subscriptions.bySubmodule(branchNameKey)).andReturn(
         emptySubscriptions);
 
@@ -293,8 +293,7 @@
         new Branch.NameKey(new Project.NameKey("dest-project"),
             "refs/heads/master");
 
-    final List<SubmoduleSubscription> subscriptionsToInsert =
-        new ArrayList<SubmoduleSubscription>();
+    List<SubmoduleSubscription> subscriptionsToInsert = new ArrayList<>();
     subscriptionsToInsert
         .add(new SubmoduleSubscription(mergedBranch, new Branch.NameKey(
             new Project.NameKey("source-a"), "refs/heads/master"), "source-a"));
@@ -351,8 +350,7 @@
         new Branch.NameKey(new Project.NameKey("dest-project"),
             "refs/heads/master");
 
-    final List<SubmoduleSubscription> subscriptionsToInsert =
-        new ArrayList<SubmoduleSubscription>();
+    List<SubmoduleSubscription> subscriptionsToInsert = new ArrayList<>();
     subscriptionsToInsert
         .add(new SubmoduleSubscription(mergedBranch, new Branch.NameKey(
             new Project.NameKey("source-a"), "refs/heads/master"), "source-a"));
@@ -409,8 +407,7 @@
         new Branch.NameKey(new Project.NameKey("dest-project"),
             "refs/heads/master");
 
-    final List<SubmoduleSubscription> subscriptionsToInsert =
-        new ArrayList<SubmoduleSubscription>();
+    List<SubmoduleSubscription> subscriptionsToInsert = new ArrayList<>();
     subscriptionsToInsert
         .add(new SubmoduleSubscription(mergedBranch, new Branch.NameKey(
             new Project.NameKey("source-a"), "refs/heads/test-a"), "source-a"));
@@ -464,14 +461,12 @@
         new Branch.NameKey(new Project.NameKey("dest-project"),
             "refs/heads/master");
 
-    final List<SubmoduleSubscription> subscriptionsToInsert =
-        new ArrayList<SubmoduleSubscription>();
+    List<SubmoduleSubscription> subscriptionsToInsert = new ArrayList<>();
     subscriptionsToInsert.add(new SubmoduleSubscription(mergedBranch,
         new Branch.NameKey(new Project.NameKey("source"), "refs/heads/master"),
         "source"));
 
-    final List<SubmoduleSubscription> oldOnesToMergedBranch =
-        new ArrayList<SubmoduleSubscription>();
+    List<SubmoduleSubscription> oldOnesToMergedBranch = new ArrayList<>();
     oldOnesToMergedBranch.add(new SubmoduleSubscription(mergedBranch,
         new Branch.NameKey(new Project.NameKey("old-source"),
             "refs/heads/master"), "old-source"));
@@ -531,15 +526,13 @@
         new SubmoduleSubscription(mergedBranch, new Branch.NameKey(new Project.NameKey(
             "old"), "refs/heads/master"), "old");
 
-    final List<SubmoduleSubscription> extractedsubscriptions =
-        new ArrayList<SubmoduleSubscription>();
+    List<SubmoduleSubscription> extractedsubscriptions = new ArrayList<>();
     extractedsubscriptions.add(new SubmoduleSubscription(mergedBranch,
         new Branch.NameKey(new Project.NameKey("new"), "refs/heads/master"),
         "new"));
     extractedsubscriptions.add(old);
 
-    final List<SubmoduleSubscription> oldOnesToMergedBranch =
-        new ArrayList<SubmoduleSubscription>();
+    List<SubmoduleSubscription> oldOnesToMergedBranch = new ArrayList<>();
     oldOnesToMergedBranch.add(old);
 
     doOnlySubscriptionTableOperations(sb.toString(), mergedBranch,
@@ -564,11 +557,8 @@
         new Branch.NameKey(new Project.NameKey("dest-project"),
             "refs/heads/master");
 
-    final List<SubmoduleSubscription> extractedsubscriptions =
-        new ArrayList<SubmoduleSubscription>();
-
-    final List<SubmoduleSubscription> oldOnesToMergedBranch =
-        new ArrayList<SubmoduleSubscription>();
+    List<SubmoduleSubscription> extractedsubscriptions = new ArrayList<>();
+    List<SubmoduleSubscription> oldOnesToMergedBranch = new ArrayList<>();
     oldOnesToMergedBranch
         .add(new SubmoduleSubscription(mergedBranch, new Branch.NameKey(
             new Project.NameKey("source-a"), "refs/heads/master"), "source-a"));
@@ -613,11 +603,10 @@
         new Change.Key(sourceMergeTip.toObjectId().getName()), new Change.Id(1),
         new Account.Id(1), sourceBranchNameKey, TimeUtil.nowTs());
 
-    final Map<Change.Id, CodeReviewCommit> mergedCommits =
-        new HashMap<Change.Id, CodeReviewCommit>();
+    final Map<Change.Id, CodeReviewCommit> mergedCommits = new HashMap<>();
     mergedCommits.put(submittedChange.getId(), codeReviewCommit);
 
-    final List<Change> submitted = new ArrayList<Change>();
+    final List<Change> submitted = new ArrayList<>();
     submitted.add(submittedChange);
 
     final Repository targetRepository = createWorkRepository();
@@ -635,7 +624,7 @@
 
     expect(schema.submoduleSubscriptions()).andReturn(subscriptions);
     final ResultSet<SubmoduleSubscription> subscribers =
-        new ListResultSet<SubmoduleSubscription>(Collections
+        new ListResultSet<>(Collections
             .singletonList(new SubmoduleSubscription(targetBranchNameKey,
                 sourceBranchNameKey, "source-project")));
     expect(subscriptions.bySubmodule(sourceBranchNameKey)).andReturn(
@@ -644,13 +633,13 @@
     expect(repoManager.openRepository(targetBranchNameKey.getParentKey()))
         .andReturn(targetRepository).anyTimes();
 
-    Capture<RefUpdate> ruCapture = new Capture<RefUpdate>();
+    Capture<RefUpdate> ruCapture = new Capture<>();
     gitRefUpdated.fire(eq(targetBranchNameKey.getParentKey()),
         capture(ruCapture));
 
     expect(schema.submoduleSubscriptions()).andReturn(subscriptions);
     final ResultSet<SubmoduleSubscription> emptySubscriptions =
-        new ListResultSet<SubmoduleSubscription>(new ArrayList<SubmoduleSubscription>());
+        new ListResultSet<>(new ArrayList<SubmoduleSubscription>());
     expect(subscriptions.bySubmodule(targetBranchNameKey)).andReturn(
         emptySubscriptions);
 
@@ -716,11 +705,10 @@
         new Change.Key(sourceMergeTip.toObjectId().getName()), new Change.Id(1),
         new Account.Id(1), sourceBranchNameKey, TimeUtil.nowTs());
 
-    final Map<Change.Id, CodeReviewCommit> mergedCommits =
-        new HashMap<Change.Id, CodeReviewCommit>();
+    final Map<Change.Id, CodeReviewCommit> mergedCommits = new HashMap<>();
     mergedCommits.put(submittedChange.getId(), codeReviewCommit);
 
-    final List<Change> submitted = new ArrayList<Change>();
+    final List<Change> submitted = new ArrayList<>();
     submitted.add(submittedChange);
 
     final Repository targetRepository = createWorkRepository();
@@ -738,7 +726,7 @@
 
     expect(schema.submoduleSubscriptions()).andReturn(subscriptions);
     final ResultSet<SubmoduleSubscription> subscribers =
-        new ListResultSet<SubmoduleSubscription>(Collections
+        new ListResultSet<>(Collections
             .singletonList(new SubmoduleSubscription(targetBranchNameKey,
                 sourceBranchNameKey, "source-project")));
     expect(subscriptions.bySubmodule(sourceBranchNameKey)).andReturn(
@@ -747,7 +735,7 @@
     expect(repoManager.openRepository(targetBranchNameKey.getParentKey()))
         .andReturn(targetRepository).anyTimes();
 
-    Capture<RefUpdate> ruCapture = new Capture<RefUpdate>();
+    Capture<RefUpdate> ruCapture = new Capture<>();
     gitRefUpdated.fire(eq(targetBranchNameKey.getParentKey()),
         capture(ruCapture));
 
@@ -803,8 +791,7 @@
         new Branch.NameKey(new Project.NameKey("dest-project"),
             "refs/heads/master");
 
-    final List<SubmoduleSubscription> subscriptionsToInsert =
-        new ArrayList<SubmoduleSubscription>();
+    List<SubmoduleSubscription> subscriptionsToInsert = new ArrayList<>();
     subscriptionsToInsert.add(new SubmoduleSubscription(mergedBranch,
         new Branch.NameKey(new Project.NameKey("source"), sourceBranchName),
         "source"));
@@ -878,10 +865,9 @@
 
     expect(schema.submoduleSubscriptions()).andReturn(subscriptions);
     expect(subscriptions.bySuperProject(mergedBranch)).andReturn(
-        new ListResultSet<SubmoduleSubscription>(previousSubscriptions));
+        new ListResultSet<>(previousSubscriptions));
 
-    SortedSet<Project.NameKey> existingProjects =
-        new TreeSet<Project.NameKey>();
+    SortedSet<Project.NameKey> existingProjects = new TreeSet<>();
 
     for (SubmoduleSubscription extracted : extractedSubscriptions) {
       existingProjects.add(extracted.getSubmodule().getParentKey());
@@ -891,8 +877,7 @@
       expect(repoManager.list()).andReturn(existingProjects);
     }
 
-    final Set<SubmoduleSubscription> alreadySubscribeds =
-        new HashSet<SubmoduleSubscription>();
+    final Set<SubmoduleSubscription> alreadySubscribeds = new HashSet<>();
     for (SubmoduleSubscription s : extractedSubscriptions) {
       if (previousSubscriptions.contains(s)) {
         alreadySubscribeds.add(s);
@@ -900,9 +885,9 @@
     }
 
     final Set<SubmoduleSubscription> subscriptionsToRemove =
-        new HashSet<SubmoduleSubscription>(previousSubscriptions);
+        new HashSet<>(previousSubscriptions);
     final List<SubmoduleSubscription> subscriptionsToInsert =
-        new ArrayList<SubmoduleSubscription>(extractedSubscriptions);
+        new ArrayList<>(extractedSubscriptions);
 
     subscriptionsToRemove.removeAll(subscriptionsToInsert);
     subscriptionsToInsert.removeAll(alreadySubscribeds);
@@ -917,7 +902,7 @@
 
     expect(schema.submoduleSubscriptions()).andReturn(subscriptions);
     expect(subscriptions.bySubmodule(mergedBranch)).andReturn(
-        new ListResultSet<SubmoduleSubscription>(new ArrayList<SubmoduleSubscription>()));
+        new ListResultSet<>(new ArrayList<SubmoduleSubscription>()));
 
     schema.close();
 
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/index/FakeIndex.java b/gerrit-server/src/test/java/com/google/gerrit/server/index/FakeIndex.java
index 4db3b27..1b6ae4e 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/index/FakeIndex.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/index/FakeIndex.java
@@ -23,11 +23,11 @@
 import com.google.gwtorm.server.ResultSet;
 
 class FakeIndex implements ChangeIndex {
-  static Schema<ChangeData> V1 = new Schema<ChangeData>(1, false,
+  static Schema<ChangeData> V1 = new Schema<>(1, false,
     ImmutableList.<FieldDef<ChangeData, ?>> of(
       ChangeField.STATUS));
 
-  static Schema<ChangeData> V2 = new Schema<ChangeData>(2, false,
+  static Schema<ChangeData> V2 = new Schema<>(2, false,
     ImmutableList.of(
       ChangeField.STATUS,
       ChangeField.PATH,
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/index/FakeQueryBuilder.java b/gerrit-server/src/test/java/com/google/gerrit/server/index/FakeQueryBuilder.java
index 2079d3d..50e5764 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/index/FakeQueryBuilder.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/index/FakeQueryBuilder.java
@@ -23,7 +23,7 @@
 public class FakeQueryBuilder extends ChangeQueryBuilder {
   FakeQueryBuilder(IndexCollection indexes) {
     super(
-        new FakeQueryBuilder.Definition<ChangeData, FakeQueryBuilder>(
+        new FakeQueryBuilder.Definition<>(
           FakeQueryBuilder.class),
         new ChangeQueryBuilder.Arguments(null, null, null, null, null, null,
           null, null, null, null, null, null, null, null, indexes, null, null,
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/project/Util.java b/gerrit-server/src/test/java/com/google/gerrit/server/project/Util.java
index e81c061..9ac8ba9 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/project/Util.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/project/Util.java
@@ -38,6 +38,8 @@
 import com.google.gerrit.server.account.GroupBackend;
 import com.google.gerrit.server.account.GroupMembership;
 import com.google.gerrit.server.account.ListGroupMembership;
+import com.google.gerrit.server.change.ChangeKindCache;
+import com.google.gerrit.server.change.ChangeKindCacheImpl;
 import com.google.gerrit.server.config.AllProjectsName;
 import com.google.gerrit.server.config.AnonymousCowardName;
 import com.google.gerrit.server.config.AnonymousCowardNameProvider;
@@ -138,7 +140,7 @@
   private final ProjectConfig parent = new ProjectConfig(allProjectsName);
 
   public Util() {
-    all = new HashMap<Project.NameKey, ProjectState>();
+    all = new HashMap<>();
     repoManager = new InMemoryRepositoryManager();
     try {
       Repository repo = repoManager.createRepository(allProjectsName);
@@ -222,6 +224,7 @@
             .toProvider(CanonicalWebUrlProvider.class);
         bind(String.class).annotatedWith(AnonymousCowardName.class)
             .toProvider(AnonymousCowardNameProvider.class);
+        bind(ChangeKindCache.class).to(ChangeKindCacheImpl.NoCache.class);
       }
     });
 
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/query/change/RegexPathPredicateTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/RegexPathPredicateTest.java
index dd7ac56..a799228 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/query/change/RegexPathPredicateTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/RegexPathPredicateTest.java
@@ -82,7 +82,7 @@
     return new RegexPathPredicate(ChangeQueryBuilder.FIELD_PATH, pattern);
   }
 
-  private static ChangeData change(String... files) {
+  private static ChangeData change(String... files) throws OrmException {
     Arrays.sort(files);
     ChangeData cd = ChangeData.createForTest(new Change.Id(1));
     cd.setCurrentFilePaths(Arrays.asList(files));
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaCreatorTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaCreatorTest.java
index 4756390..15a66ab 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaCreatorTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaCreatorTest.java
@@ -129,6 +129,7 @@
     assertNotNull(codeReview);
     assertEquals("Code-Review", codeReview.getName());
     assertEquals("CR", codeReview.getAbbreviation());
+    assertEquals(0, codeReview.getDefaultValue());
     assertEquals("MaxWithBlock", codeReview.getFunctionName());
     assertTrue(codeReview.isCopyMinScore());
     assertValueRange(codeReview, 2, 1, 0, -1, -2);
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/util/IdGeneratorTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/util/IdGeneratorTest.java
index 5546410..a2228d8 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/util/IdGeneratorTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/util/IdGeneratorTest.java
@@ -24,7 +24,7 @@
 public class IdGeneratorTest {
   @Test
   public void test1234() {
-    final HashSet<Integer> seen = new HashSet<Integer>();
+    final HashSet<Integer> seen = new HashSet<>();
     for (int i = 0; i < 1 << 16; i++) {
       final int e = IdGenerator.mix(i);
       assertTrue("no duplicates", seen.add(e));
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/util/SubmoduleSectionParserTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/util/SubmoduleSectionParserTest.java
index edd79241..d87888f 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/util/SubmoduleSectionParserTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/util/SubmoduleSectionParserTest.java
@@ -64,8 +64,7 @@
 
   @Test
   public void testSubmodulesParseWithCorrectSections() throws Exception {
-    final Map<String, SubmoduleSection> sectionsToReturn =
-        new TreeMap<String, SubmoduleSection>();
+    final Map<String, SubmoduleSection> sectionsToReturn = new TreeMap<>();
     sectionsToReturn.put("a", new SubmoduleSection("ssh://localhost/a", "a",
         "."));
     sectionsToReturn.put("b", new SubmoduleSection("ssh://localhost/b", "b",
@@ -77,7 +76,7 @@
     sectionsToReturn.put("e", new SubmoduleSection("ssh://localhost/e.git", "e",
         "."));
 
-    final Map<String, String> reposToBeFound = new HashMap<String, String>();
+    Map<String, String> reposToBeFound = new HashMap<>();
     reposToBeFound.put("a", "a");
     reposToBeFound.put("b", "b");
     reposToBeFound.put("c", "test/c");
@@ -88,8 +87,7 @@
         new Branch.NameKey(new Project.NameKey("super-project"),
             "refs/heads/master");
 
-    final List<SubmoduleSubscription> expectedSubscriptions =
-        new ArrayList<SubmoduleSubscription>();
+    List<SubmoduleSubscription> expectedSubscriptions = new ArrayList<>();
     expectedSubscriptions
         .add(new SubmoduleSubscription(superBranchNameKey, new Branch.NameKey(
             new Project.NameKey("a"), "refs/heads/master"), "a"));
@@ -112,8 +110,7 @@
 
   @Test
   public void testSubmodulesParseWithAnInvalidSection() throws Exception {
-    final Map<String, SubmoduleSection> sectionsToReturn =
-        new TreeMap<String, SubmoduleSection>();
+    final Map<String, SubmoduleSection> sectionsToReturn = new TreeMap<>();
     sectionsToReturn.put("a", new SubmoduleSection("ssh://localhost/a", "a",
         "."));
     // This one is invalid since "b" is not a recognized project
@@ -127,7 +124,7 @@
         "."));
 
     // "b" will not be in this list
-    final Map<String, String> reposToBeFound = new HashMap<String, String>();
+    Map<String, String> reposToBeFound = new HashMap<>();
     reposToBeFound.put("a", "a");
     reposToBeFound.put("c", "test/c");
     reposToBeFound.put("d", "d");
@@ -137,8 +134,7 @@
         new Branch.NameKey(new Project.NameKey("super-project"),
             "refs/heads/master");
 
-    final List<SubmoduleSubscription> expectedSubscriptions =
-        new ArrayList<SubmoduleSubscription>();
+    List<SubmoduleSubscription> expectedSubscriptions = new ArrayList<>();
     expectedSubscriptions
         .add(new SubmoduleSubscription(superBranchNameKey, new Branch.NameKey(
             new Project.NameKey("a"), "refs/heads/master"), "a"));
@@ -158,8 +154,7 @@
 
   @Test
   public void testSubmoduleSectionToOtherServer() throws Exception {
-    Map<String, SubmoduleSection> sectionsToReturn =
-        new HashMap<String, SubmoduleSection>();
+    Map<String, SubmoduleSection> sectionsToReturn = new HashMap<>();
     // The url is not to this server.
     sectionsToReturn.put("a", new SubmoduleSection("ssh://review.source.com/a",
         "a", "."));
@@ -171,8 +166,7 @@
 
   @Test
   public void testProjectNotFound() throws Exception {
-    Map<String, SubmoduleSection> sectionsToReturn =
-        new HashMap<String, SubmoduleSection>();
+    Map<String, SubmoduleSection> sectionsToReturn = new HashMap<>();
     sectionsToReturn.put("a", new SubmoduleSection("ssh://localhost/a", "a",
         "."));
 
@@ -183,8 +177,7 @@
 
   @Test
   public void testProjectWithSlashesNotFound() throws Exception {
-    Map<String, SubmoduleSection> sectionsToReturn =
-        new HashMap<String, SubmoduleSection>();
+    Map<String, SubmoduleSection> sectionsToReturn = new HashMap<>();
     sectionsToReturn.put("project", new SubmoduleSection(
         "ssh://localhost/company/tools/project", "project", "."));
 
@@ -222,12 +215,12 @@
           }
           if (projectNameCandidate.equals(reposToBeFound.get(id))) {
             expect(repoManager.list()).andReturn(
-                new TreeSet<Project.NameKey>(Collections
-                    .singletonList(new Project.NameKey(projectNameCandidate))));
+                new TreeSet<>(Collections.singletonList(
+                    new Project.NameKey(projectNameCandidate))));
             break;
           } else {
             expect(repoManager.list()).andReturn(
-                new TreeSet<Project.NameKey>(Collections.<Project.NameKey> emptyList()));
+                new TreeSet<>(Collections.<Project.NameKey> emptyList()));
           }
         }
       }
diff --git a/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryDatabase.java b/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryDatabase.java
index bc344fa..6353904 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryDatabase.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryDatabase.java
@@ -91,7 +91,7 @@
 
       // Build the access layer around the connection factory.
       //
-      database = new Database<ReviewDb>(dataSource, ReviewDb.class);
+      database = new Database<>(dataSource, ReviewDb.class);
 
     } catch (SQLException e) {
       throw new OrmException(e);
diff --git a/gerrit-server/src/test/java/com/google/gerrit/testutil/MockingTestCase.java b/gerrit-server/src/test/java/com/google/gerrit/testutil/MockingTestCase.java
index f0c7ce1..569a57f 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/testutil/MockingTestCase.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/testutil/MockingTestCase.java
@@ -138,8 +138,8 @@
       usePowerMock = PowerMockRunner.class.isAssignableFrom(runWith.value());
     }
 
-    mocks = new ArrayList<Object>();
-    mockControls = new ArrayList<IMocksControl>();
+    mocks = new ArrayList<>();
+    mockControls = new ArrayList<>();
     mocksReplayed = false;
   }
 
diff --git a/gerrit-server/src/test/java/com/google/gerrit/testutil/SetMatcher.java b/gerrit-server/src/test/java/com/google/gerrit/testutil/SetMatcher.java
index 2e6b68e..f1e7b7b 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/testutil/SetMatcher.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/testutil/SetMatcher.java
@@ -29,7 +29,7 @@
  */
 public class SetMatcher<T> implements IArgumentMatcher {
   public static <S extends Iterable<T>,T> S setEq(S expected) {
-    EasyMock.reportMatcher(new SetMatcher<T>(expected));
+    EasyMock.reportMatcher(new SetMatcher<>(expected));
     return null;
   }
 
diff --git a/gerrit-server/src/test/java/com/google/gerrit/testutil/log/CollectionAppender.java b/gerrit-server/src/test/java/com/google/gerrit/testutil/log/CollectionAppender.java
index 43179e3..05f52c0 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/testutil/log/CollectionAppender.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/testutil/log/CollectionAppender.java
@@ -29,7 +29,7 @@
   private Collection<LoggingEvent> events;
 
   public CollectionAppender() {
-    events = new LinkedList<LoggingEvent>();
+    events = new LinkedList<>();
   }
 
   public CollectionAppender(Collection<LoggingEvent> events) {
diff --git a/gerrit-server/src/test/java/com/google/gerrit/testutil/log/LogUtil.java b/gerrit-server/src/test/java/com/google/gerrit/testutil/log/LogUtil.java
index f8b73fb..e3c83ca 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/testutil/log/LogUtil.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/testutil/log/LogUtil.java
@@ -59,7 +59,7 @@
       this.additive = logger.getAdditivity();
 
       Enumeration<?> appenders = logger.getAllAppenders();
-      this.appenders = new ArrayList<Appender>();
+      this.appenders = new ArrayList<>();
       while (appenders.hasMoreElements()) {
         Object appender = appenders.nextElement();
         if (appender instanceof Appender) {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandFactoryProvider.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandFactoryProvider.java
index a2e6542..f394766 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandFactoryProvider.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandFactoryProvider.java
@@ -246,7 +246,7 @@
 
   /** Split a command line into a string array. */
   static public String[] split(String commandLine) {
-    final List<String> list = new ArrayList<String>();
+    final List<String> list = new ArrayList<>();
     boolean inquote = false;
     boolean inDblQuote = false;
     StringBuilder r = new StringBuilder();
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DatabasePubKeyAuth.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DatabasePubKeyAuth.java
index 9354da3..cc7b637 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DatabasePubKeyAuth.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DatabasePubKeyAuth.java
@@ -77,7 +77,7 @@
   }
 
   private static Set<PublicKey> myHostKeys(KeyPairProvider p) {
-    final Set<PublicKey> keys = new HashSet<PublicKey>(2);
+    final Set<PublicKey> keys = new HashSet<>(2);
     addPublicKey(keys, p, KeyPairProvider.SSH_RSA);
     addPublicKey(keys, p, KeyPairProvider.SSH_DSS);
     return keys;
@@ -183,7 +183,7 @@
       try {
         final BufferedReader br = new BufferedReader(new FileReader(path));
         try {
-          final Set<PublicKey> keys = new HashSet<PublicKey>();
+          final Set<PublicKey> keys = new HashSet<>();
           String line;
           while ((line = br.readLine()) != null) {
             line = line.trim();
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DispatchCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DispatchCommand.java
index fa5ab53..a7748ff 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DispatchCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DispatchCommand.java
@@ -52,7 +52,7 @@
   private String commandName;
 
   @Argument(index = 1, multiValued = true, metaVar = "ARG")
-  private List<String> args = new ArrayList<String>();
+  private List<String> args = new ArrayList<>();
 
   @Inject
   DispatchCommand(final Provider<CurrentUser> cu,
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/HostKeyProvider.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/HostKeyProvider.java
index f901a77..241f853 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/HostKeyProvider.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/HostKeyProvider.java
@@ -42,7 +42,7 @@
     final File rsaKey = site.ssh_rsa;
     final File dsaKey = site.ssh_dsa;
 
-    final List<String> stdKeys = new ArrayList<String>(2);
+    final List<String> stdKeys = new ArrayList<>(2);
     if (rsaKey.exists()) {
       stdKeys.add(rsaKey.getAbsolutePath());
     }
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java
index 7a02fb9..6f34172 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java
@@ -18,6 +18,8 @@
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.SECONDS;
 
+import com.google.common.base.Strings;
+import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.gerrit.common.Version;
 import com.google.gerrit.extensions.events.LifecycleListener;
@@ -43,6 +45,7 @@
 import org.apache.sshd.common.KeyExchange;
 import org.apache.sshd.common.KeyPairProvider;
 import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.RequestHandler;
 import org.apache.sshd.common.Session;
 import org.apache.sshd.common.Signature;
 import org.apache.sshd.common.SshdSocketAddress;
@@ -51,11 +54,11 @@
 import org.apache.sshd.common.cipher.AES192CBC;
 import org.apache.sshd.common.cipher.AES256CBC;
 import org.apache.sshd.common.cipher.AES256CTR;
+import org.apache.sshd.common.cipher.ARCFOUR128;
+import org.apache.sshd.common.cipher.ARCFOUR256;
 import org.apache.sshd.common.cipher.BlowfishCBC;
 import org.apache.sshd.common.cipher.CipherNone;
 import org.apache.sshd.common.cipher.TripleDESCBC;
-import org.apache.sshd.common.cipher.ARCFOUR128;
-import org.apache.sshd.common.cipher.ARCFOUR256;
 import org.apache.sshd.common.compression.CompressionNone;
 import org.apache.sshd.common.file.FileSystemFactory;
 import org.apache.sshd.common.file.FileSystemView;
@@ -78,6 +81,7 @@
 import org.apache.sshd.common.random.JceRandom;
 import org.apache.sshd.common.random.SingletonRandomFactory;
 import org.apache.sshd.common.session.AbstractSession;
+import org.apache.sshd.common.session.ConnectionService;
 import org.apache.sshd.common.signature.SignatureDSA;
 import org.apache.sshd.common.signature.SignatureRSA;
 import org.apache.sshd.common.util.Buffer;
@@ -90,6 +94,10 @@
 import org.apache.sshd.server.auth.gss.GSSAuthenticator;
 import org.apache.sshd.server.auth.gss.UserAuthGSS;
 import org.apache.sshd.server.channel.ChannelSession;
+import org.apache.sshd.server.global.CancelTcpipForwardHandler;
+import org.apache.sshd.server.global.KeepAliveHandler;
+import org.apache.sshd.server.global.NoMoreSessionsHandler;
+import org.apache.sshd.server.global.TcpipForwardHandler;
 import org.apache.sshd.server.kex.DHG1;
 import org.apache.sshd.server.kex.DHG14;
 import org.apache.sshd.server.session.SessionFactory;
@@ -100,6 +108,7 @@
 import java.io.File;
 import java.io.IOException;
 import java.net.InetAddress;
+import java.net.InetSocketAddress;
 import java.net.SocketAddress;
 import java.net.UnknownHostException;
 import java.security.InvalidKeyException;
@@ -144,7 +153,9 @@
   private final boolean keepAlive;
   private final List<HostKey> hostKeys;
   private volatile IoAcceptor acceptor;
+  private final Config cfg;
 
+  @SuppressWarnings("unchecked")
   @Inject
   SshDaemon(final CommandFactory commandFactory, final NoShell noShell,
       final PublickeyAuthenticator userAuth,
@@ -155,6 +166,7 @@
       @SshAdvertisedAddresses final List<String> advertised) {
     setPort(IANA_SSH_PORT /* never used */);
 
+    this.cfg = cfg;
     this.listen = listen;
     this.advertised = advertised;
     keepAlive = cfg.getBoolean("sshd", "tcpkeepalive", true);
@@ -252,6 +264,12 @@
         return new GerritServerSession(server, ioSession);
       }
     });
+    setGlobalRequestHandlers(Arrays.<RequestHandler<ConnectionService>> asList(
+          new KeepAliveHandler(),
+          new NoMoreSessionsHandler(),
+          new TcpipForwardHandler(),
+          new CancelTcpipForwardHandler()
+        ));
 
     hostKeys = computeHostKeys();
   }
@@ -276,7 +294,14 @@
       acceptor = createAcceptor();
 
       try {
+        String listenAddress = cfg.getString("sshd", null, "listenAddress");
+        boolean rewrite = !Strings.isNullOrEmpty(listenAddress)
+            && listenAddress.endsWith(":0");
         acceptor.bind(listen);
+        if (rewrite) {
+          SocketAddress bound = Iterables.getOnlyElement(acceptor.getBoundAddresses());
+          cfg.setString("sshd", null, "listenAddress", format((InetSocketAddress)bound));
+        }
       } catch (IOException e) {
         throw new IllegalStateException("Cannot bind to " + addressList(), e);
       }
@@ -286,6 +311,10 @@
     }
   }
 
+  private static String format(InetSocketAddress s) {
+    return String.format("%s:%d", s.getAddress().getHostAddress(), s.getPort());
+  }
+
   @Override
   public synchronized void stop() {
     if (acceptor != null) {
@@ -314,7 +343,7 @@
     }
 
     final List<PublicKey> keys = myHostKeys();
-    final ArrayList<HostKey> r = new ArrayList<HostKey>();
+    final List<HostKey> r = new ArrayList<>();
     for (final PublicKey pub : keys) {
       final Buffer buf = new Buffer();
       buf.putRawPublicKey(pub);
@@ -333,7 +362,7 @@
 
   private List<PublicKey> myHostKeys() {
     final KeyPairProvider p = getKeyPairProvider();
-    final List<PublicKey> keys = new ArrayList<PublicKey>(2);
+    final List<PublicKey> keys = new ArrayList<>(2);
     addPublicKey(keys, p, KeyPairProvider.SSH_RSA);
     addPublicKey(keys, p, KeyPairProvider.SSH_DSS);
     return keys;
@@ -373,7 +402,7 @@
 
   @SuppressWarnings("unchecked")
   private void initCiphers(final Config cfg) {
-    final List<NamedFactory<Cipher>> a = new LinkedList<NamedFactory<Cipher>>();
+    final List<NamedFactory<Cipher>> a = new LinkedList<>();
     a.add(new AES128CBC.Factory());
     a.add(new TripleDESCBC.Factory());
     a.add(new BlowfishCBC.Factory());
@@ -416,7 +445,7 @@
   @SafeVarargs
   private static <T> List<NamedFactory<T>> filter(final Config cfg,
       final String key, final NamedFactory<T>... avail) {
-    final ArrayList<NamedFactory<T>> def = new ArrayList<NamedFactory<T>>();
+    final ArrayList<NamedFactory<T>> def = new ArrayList<>();
     for (final NamedFactory<T> n : avail) {
       if (n == null) {
         break;
@@ -579,6 +608,11 @@
           @Override
           public SshFile getFile(String file) {
             return null;
+          }
+
+          @Override
+          public FileSystemView getNormalizedView() {
+            return null;
           }};
       }
     });
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshKeyCacheImpl.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshKeyCacheImpl.java
index 0a1f708..2ec67a4 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshKeyCacheImpl.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshKeyCacheImpl.java
@@ -135,7 +135,7 @@
           return NO_SUCH_USER;
         }
 
-        final List<SshKeyCacheEntry> kl = new ArrayList<SshKeyCacheEntry>(4);
+        final List<SshKeyCacheEntry> kl = new ArrayList<>(4);
         for (AccountSshKey k : db.accountSshKeys().byAccount(
             user.getAccountId())) {
           if (k.isValid()) {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshScope.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshScope.java
index 9067b9b..f8b5ddb 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshScope.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshScope.java
@@ -144,8 +144,7 @@
     }
   }
 
-  private static final ThreadLocal<Context> current =
-      new ThreadLocal<Context>();
+  private static final ThreadLocal<Context> current = new ThreadLocal<>();
 
   private static Context requireContext() {
     final Context ctx = current.get();
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshSession.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshSession.java
index 04bf603..2e3d113 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshSession.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshSession.java
@@ -26,8 +26,7 @@
 /** Global data related to an active SSH connection. */
 public class SshSession {
   /** ServerSession attribute key for this object instance. */
-  public static final AttributeKey<SshSession> KEY =
-      new AttributeKey<SshSession>();
+  public static final AttributeKey<SshSession> KEY = new AttributeKey<>();
 
   private final int sessionId;
   private final SocketAddress remoteAddress;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SuExec.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SuExec.java
index 298a099..77738d0 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SuExec.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SuExec.java
@@ -59,7 +59,7 @@
   private SocketAddress peerAddress;
 
   @Argument(index = 0, multiValued = true, metaVar = "COMMAND")
-  private List<String> args = new ArrayList<String>();
+  private List<String> args = new ArrayList<>();
 
   private final AtomicReference<Command> atomicCmd;
 
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminSetParent.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminSetParent.java
index 8db6431..d448bd2 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminSetParent.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminSetParent.java
@@ -63,11 +63,11 @@
 
   @Option(name = "--exclude", metaVar = "NAME",
       usage = "child project of old parent project which should not be reparented")
-  private List<ProjectControl> excludedChildren = new ArrayList<ProjectControl>();
+  private List<ProjectControl> excludedChildren = new ArrayList<>();
 
   @Argument(index = 0, required = false, multiValued = true, metaVar = "NAME",
       usage = "projects to modify")
-  private List<ProjectControl> children = new ArrayList<ProjectControl>();
+  private List<ProjectControl> children = new ArrayList<>();
 
   @Inject
   private ProjectCache projectCache;
@@ -95,7 +95,7 @@
     }
 
     final StringBuilder err = new StringBuilder();
-    final Set<Project.NameKey> grandParents = new HashSet<Project.NameKey>();
+    final Set<Project.NameKey> grandParents = new HashSet<>();
 
     grandParents.add(allProjectsName);
 
@@ -187,12 +187,12 @@
   private List<Project.NameKey> getChildrenForReparenting(final ProjectControl parent) {
     final List<Project.NameKey> childProjects = Lists.newArrayList();
     final List<Project.NameKey> excluded =
-      new ArrayList<Project.NameKey>(excludedChildren.size());
+        new ArrayList<>(excludedChildren.size());
     for (final ProjectControl excludedChild : excludedChildren) {
       excluded.add(excludedChild.getProject().getNameKey());
     }
     final List<Project.NameKey> automaticallyExcluded =
-      new ArrayList<Project.NameKey>(excludedChildren.size());
+        new ArrayList<>(excludedChildren.size());
     if (newParentKey != null) {
       automaticallyExcluded.addAll(getAllParents(newParentKey));
     }
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/BanCommitCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/BanCommitCommand.java
index 1d4b900..da850ed 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/BanCommitCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/BanCommitCommand.java
@@ -47,7 +47,7 @@
 
   @Argument(index = 1, required = true, multiValued = true, metaVar = "COMMIT",
       usage = "commit(s) that should be banned")
-  private List<ObjectId> commitsToBan = new ArrayList<ObjectId>();
+  private List<ObjectId> commitsToBan = new ArrayList<>();
 
   @Inject
   private BanCommit.Factory banCommitFactory;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateAccountCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateAccountCommand.java
index aef1560..aeb69d0 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateAccountCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateAccountCommand.java
@@ -42,7 +42,7 @@
 @CommandMetaData(name = "create-account", description = "Create a new batch/role account")
 final class CreateAccountCommand extends SshCommand {
   @Option(name = "--group", aliases = {"-g"}, metaVar = "GROUP", usage = "groups to add account to")
-  private List<AccountGroup.Id> groups = new ArrayList<AccountGroup.Id>();
+  private List<AccountGroup.Id> groups = new ArrayList<>();
 
   @Option(name = "--full-name", metaVar = "NAME", usage = "display name of the account")
   private String fullName;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateGroupCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateGroupCommand.java
index 91996b1..75194dc 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateGroupCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateGroupCommand.java
@@ -53,7 +53,7 @@
   @Argument(index = 0, required = true, metaVar = "GROUP", usage = "name of group to be created")
   private String groupName;
 
-  private final Set<Account.Id> initialMembers = new HashSet<Account.Id>();
+  private final Set<Account.Id> initialMembers = new HashSet<>();
 
   @Option(name = "--member", aliases = {"-m"}, metaVar = "USERNAME", usage = "initial set of users to become members of the group")
   void addMember(final Account.Id id) {
@@ -63,7 +63,7 @@
   @Option(name = "--visible-to-all", usage = "to make the group visible to all registered users")
   private boolean visibleToAll;
 
-  private final Set<AccountGroup.UUID> initialGroups = new HashSet<AccountGroup.UUID>();
+  private final Set<AccountGroup.UUID> initialGroups = new HashSet<>();
 
   @Option(name = "--group", aliases = "-g", metaVar = "GROUP", usage = "initial set of groups to be included in the group")
   void addGroup(final AccountGroup.UUID id) {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/FlushCaches.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/FlushCaches.java
index 40152b0..1de4636 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/FlushCaches.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/FlushCaches.java
@@ -39,7 +39,7 @@
   private static final String WEB_SESSIONS = "web_sessions";
 
   @Option(name = "--cache", usage = "flush named cache", metaVar = "NAME")
-  private List<String> caches = new ArrayList<String>();
+  private List<String> caches = new ArrayList<>();
 
   @Option(name = "--all", usage = "flush all caches")
   private boolean all;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/GarbageCollectionCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/GarbageCollectionCommand.java
index 821701d..a1099dc 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/GarbageCollectionCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/GarbageCollectionCommand.java
@@ -51,7 +51,7 @@
 
   @Argument(index = 0, required = false, multiValued = true, metaVar = "NAME",
       usage = "projects for which the Git garbage collection should be run")
-  private List<ProjectControl> projects = new ArrayList<ProjectControl>();
+  private List<ProjectControl> projects = new ArrayList<>();
 
   @Inject
   private ProjectCache projectCache;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/KillCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/KillCommand.java
index 83e88e5..d8c3403 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/KillCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/KillCommand.java
@@ -35,7 +35,7 @@
   @Inject
   private WorkQueue workQueue;
 
-  private final Set<Integer> taskIds = new HashSet<Integer>();
+  private final Set<Integer> taskIds = new HashSet<>();
 
   @Argument(index = 0, multiValued = true, required = true, metaVar = "ID")
   void addTaskId(final String taskId) {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/QueryShell.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/QueryShell.java
index 77c5df4..39ec81f5 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/QueryShell.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/QueryShell.java
@@ -306,7 +306,7 @@
     try {
       ResultSet rs = meta.getIndexInfo(null, null, tableName, false, true);
       try {
-        Map<String, IndexInfo> indexes = new TreeMap<String, IndexInfo>();
+        Map<String, IndexInfo> indexes = new TreeMap<>();
         while (rs.next()) {
           final String indexName = rs.getString("INDEX_NAME");
           IndexInfo def = indexes.get(indexName);
@@ -550,7 +550,7 @@
       widths[c] = columnMap[c].name.length();
     }
 
-    final List<String[]> rows = new ArrayList<String[]>();
+    final List<String[]> rows = new ArrayList<>();
     while (alreadyOnRow || rs.next()) {
       final String[] row = new String[columnMap.length];
       for (int c = 0; c < colCnt; c++) {
@@ -759,7 +759,7 @@
   private static class IndexInfo {
     String name;
     boolean unique;
-    final Map<Integer, String> columns = new TreeMap<Integer, String>();
+    final Map<Integer, String> columns = new TreeMap<>();
     final StringBuilder filter = new StringBuilder();
 
     void addColumn(int pos, String column) {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java
index a3c2cf5..abb788d 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java
@@ -70,8 +70,8 @@
   @Inject
   private DynamicSet<PostReceiveHook> postReceiveHooks;
 
-  private final Set<Account.Id> reviewerId = new HashSet<Account.Id>();
-  private final Set<Account.Id> ccId = new HashSet<Account.Id>();
+  private final Set<Account.Id> reviewerId = new HashSet<>();
+  private final Set<Account.Id> ccId = new HashSet<>();
 
   @Option(name = "--reviewer", aliases = {"--re"}, metaVar = "EMAIL", usage = "request reviewer for change(s)")
   void addReviewer(final Account.Id id) {
@@ -158,7 +158,7 @@
 
         Map<String, Ref> allRefs =
             rp.getRepository().getRefDatabase().getRefs(RefDatabase.ALL);
-        List<Ref> hidden = new ArrayList<Ref>();
+        List<Ref> hidden = new ArrayList<>();
         for (Ref ref : allRefs.values()) {
           if (!adv.containsKey(ref.getName())) {
             hidden.add(ref);
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java
index e30d41b..107394b 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java
@@ -73,7 +73,7 @@
     return parser;
   }
 
-  private final Set<PatchSet> patchSets = new HashSet<PatchSet>();
+  private final Set<PatchSet> patchSets = new HashSet<>();
 
   @Argument(index = 0, required = true, multiValued = true, metaVar = "{COMMIT | CHANGE,PATCHSET}", usage = "list of commits or patch sets to review")
   void addPatchSetId(final String token) {
@@ -282,7 +282,7 @@
         patches = db.patchSets().byRevisionRange(id, id.max());
       }
 
-      final Set<PatchSet> matches = new HashSet<PatchSet>();
+      final Set<PatchSet> matches = new HashSet<>();
       for (final PatchSet ps : patches) {
         final Change change = db.changes().get(ps.getId().getParentKey());
         if (inProject(change) && inBranch(change)) {
@@ -348,7 +348,7 @@
 
   @Override
   protected void parseCommandLine() throws UnloggedFailure {
-    optionList = new ArrayList<ApproveOption>();
+    optionList = new ArrayList<>();
     customLabels = Maps.newHashMap();
 
     ProjectControl allProjectsControl;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetAccountCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetAccountCommand.java
index f3f35db..5088424 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetAccountCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetAccountCommand.java
@@ -71,16 +71,16 @@
   private boolean inactive;
 
   @Option(name = "--add-email", metaVar = "EMAIL", usage = "email addresses to add to the account")
-  private List<String> addEmails = new ArrayList<String>();
+  private List<String> addEmails = new ArrayList<>();
 
   @Option(name = "--delete-email", metaVar = "EMAIL", usage = "email addresses to delete from the account")
-  private List<String> deleteEmails = new ArrayList<String>();
+  private List<String> deleteEmails = new ArrayList<>();
 
   @Option(name = "--add-ssh-key", metaVar = "-|KEY", usage = "public keys to add to the account")
-  private List<String> addSshKeys = new ArrayList<String>();
+  private List<String> addSshKeys = new ArrayList<>();
 
   @Option(name = "--delete-ssh-key", metaVar = "-|KEY", usage = "public keys to delete from the account")
-  private List<String> deleteSshKeys = new ArrayList<String>();
+  private List<String> deleteSshKeys = new ArrayList<>();
 
   @Option(name = "--http-password", metaVar = "PASSWORD", usage = "password for HTTP authentication for the account")
   private String httpPassword;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetReviewersCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetReviewersCommand.java
index 41d3e97..8ce935c 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetReviewersCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetReviewersCommand.java
@@ -56,7 +56,7 @@
   private ProjectControl projectControl;
 
   @Option(name = "--add", aliases = {"-a"}, metaVar = "REVIEWER", usage = "user or group that should be added as reviewer")
-  private List<String> toAdd = new ArrayList<String>();
+  private List<String> toAdd = new ArrayList<>();
 
   @Option(name = "--remove", aliases = {"-r"}, metaVar = "REVIEWER", usage = "user that should be removed from the reviewer list")
   void optionRemove(Account.Id who) {
@@ -92,8 +92,8 @@
   @Inject
   private ChangesCollection changesCollection;
 
-  private Set<Account.Id> toRemove = new HashSet<Account.Id>();
-  private Set<Change.Id> changes = new HashSet<Change.Id>();
+  private Set<Account.Id> toRemove = new HashSet<>();
+  private Set<Change.Id> changes = new HashSet<>();
 
   @Override
   protected void run() throws UnloggedFailure {
@@ -161,7 +161,7 @@
 
   private Set<Change.Id> parseChangeId(String idstr)
       throws UnloggedFailure, OrmException {
-    Set<Change.Id> matched = new HashSet<Change.Id>(4);
+    Set<Change.Id> matched = new HashSet<>(4);
     boolean isCommit = idstr.matches("^([0-9a-fA-F]{4," + RevId.LEN + "})$");
 
     // By newer style changeKey?
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowConnections.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowConnections.java
index 536ad88..3d1ed3f 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowConnections.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowConnections.java
@@ -86,7 +86,7 @@
     }
 
     final List<IoSession> list =
-        new ArrayList<IoSession>(acceptor.getManagedSessions().values());
+        new ArrayList<>(acceptor.getManagedSessions().values());
     Collections.sort(list, new Comparator<IoSession>() {
       @Override
       public int compare(IoSession arg0, IoSession arg1) {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/StreamEvents.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/StreamEvents.java
index c55c7ed..6da858a 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/StreamEvents.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/StreamEvents.java
@@ -59,7 +59,7 @@
 
   /** Queue of events to stream to the connected user. */
   private final LinkedBlockingQueue<ChangeEvent> queue =
-      new LinkedBlockingQueue<ChangeEvent>(MAX_EVENTS);
+      new LinkedBlockingQueue<>(MAX_EVENTS);
 
   private final Gson gson = new Gson();
 
diff --git a/gerrit-util-cli/src/main/java/com/google/gerrit/util/cli/CmdLineParser.java b/gerrit-util-cli/src/main/java/com/google/gerrit/util/cli/CmdLineParser.java
index 7fc6d6f..c60c0d2 100644
--- a/gerrit-util-cli/src/main/java/com/google/gerrit/util/cli/CmdLineParser.java
+++ b/gerrit-util-cli/src/main/java/com/google/gerrit/util/cli/CmdLineParser.java
@@ -131,7 +131,7 @@
     out.write(name);
 
     char next = '?';
-    List<NamedOptionDef> booleans = new ArrayList<NamedOptionDef>();
+    List<NamedOptionDef> booleans = new ArrayList<>();
     for (@SuppressWarnings("rawtypes") OptionHandler handler : parser.options) {
       if (handler.option instanceof NamedOptionDef) {
         NamedOptionDef n = (NamedOptionDef) handler.option;
diff --git a/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java b/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
index 78d5fff..abc5ae3 100644
--- a/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
+++ b/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
@@ -201,7 +201,7 @@
   }
 
   private Injector createDbInjector() {
-    final List<Module> modules = new ArrayList<Module>();
+    final List<Module> modules = new ArrayList<>();
     if (sitePath != null) {
       Module sitePathModule = new AbstractModule() {
         @Override
@@ -249,7 +249,7 @@
   }
 
   private Injector createCfgInjector() {
-    final List<Module> modules = new ArrayList<Module>();
+    final List<Module> modules = new ArrayList<>();
     if (sitePath == null) {
       // If we didn't get the site path from the system property
       // we need to get it from the database, as that's our old
@@ -272,7 +272,7 @@
   }
 
   private Injector createSysInjector() {
-    final List<Module> modules = new ArrayList<Module>();
+    final List<Module> modules = new ArrayList<>();
     modules.add(new WorkQueue.Module());
     modules.add(new ChangeHookRunner.Module());
     modules.add(new ReceiveCommitsExecutorModule());
@@ -314,7 +314,7 @@
   }
 
   private Injector createSshInjector() {
-    final List<Module> modules = new ArrayList<Module>();
+    final List<Module> modules = new ArrayList<>();
     modules.add(sysInjector.getInstance(SshModule.class));
     modules.add(new SshHostKeyModule());
     modules.add(new DefaultCommandModule(false));
@@ -322,7 +322,7 @@
   }
 
   private Injector createWebInjector() {
-    final List<Module> modules = new ArrayList<Module>();
+    final List<Module> modules = new ArrayList<>();
     modules.add(RequestContextFilter.module());
     modules.add(AllRequestFilter.module());
     modules.add(sysInjector.getInstance(GitOverHttpModule.class));
diff --git a/lib/BUCK b/lib/BUCK
index 17d40a4..a6a10e7 100644
--- a/lib/BUCK
+++ b/lib/BUCK
@@ -107,15 +107,15 @@
 
 maven_jar(
   name = 'jsch',
-  id = 'com.jcraft:jsch:0.1.50',
-  sha1 = 'fae4a0b1f2a96cb8f58f38da2650814c991cea01',
+  id = 'com.jcraft:jsch:0.1.51',
+  sha1 = '6ceee2696b07cc320d0e1aaea82c7b40768aca0f',
   license = 'jsch',
 )
 
 maven_jar(
   name = 'servlet-api-3_1',
-  id = 'org.apache.tomcat:tomcat-servlet-api:8.0.0-RC10',
-  sha1 = '975935b6203073938dfeeb28e4effc3b094c4fc4',
+  id = 'org.apache.tomcat:tomcat-servlet-api:8.0.5',
+  sha1 = '9ef01afc25481b82aa8f3615db536869f2dc961e',
   license = 'Apache2.0',
   exclude = ['META-INF/NOTICE', 'META-INF/LICENSE'],
 )
diff --git a/lib/asciidoctor/java/AsciiDoctor.java b/lib/asciidoctor/java/AsciiDoctor.java
index 933b929..9e48641 100644
--- a/lib/asciidoctor/java/AsciiDoctor.java
+++ b/lib/asciidoctor/java/AsciiDoctor.java
@@ -58,10 +58,10 @@
 
   @Option(name = "-a", usage =
       "a list of attributes, in the form key or key=value pair")
-  private List<String> attributes = new ArrayList<String>();
+  private List<String> attributes = new ArrayList<>();
 
   @Argument(usage = "input files")
-  private List<String> inputFiles = new ArrayList<String>();
+  private List<String> inputFiles = new ArrayList<>();
 
   public static String mapInFileToOutFile(
       String inFile, String inExt, String outExt) {
@@ -97,7 +97,7 @@
   }
 
   private Map<String, Object> getAttributes() {
-    Map<String, Object> attributeValues = new HashMap<String, Object>();
+    Map<String, Object> attributeValues = new HashMap<>();
 
     for (String attribute : attributes) {
       int equalsIndex = attribute.indexOf('=');
diff --git a/lib/asciidoctor/java/DocIndexer.java b/lib/asciidoctor/java/DocIndexer.java
index cf44662..4bcddbb 100644
--- a/lib/asciidoctor/java/DocIndexer.java
+++ b/lib/asciidoctor/java/DocIndexer.java
@@ -67,7 +67,7 @@
   private String outExt = ".html";
 
   @Argument(usage = "input files")
-  private List<String> inputFiles = new ArrayList<String>();
+  private List<String> inputFiles = new ArrayList<>();
 
   private void invoke(String... parameters) throws IOException {
     CmdLineParser parser = new CmdLineParser(this);
diff --git a/lib/jetty/BUCK b/lib/jetty/BUCK
index 9637598..a6fc4a7 100644
--- a/lib/jetty/BUCK
+++ b/lib/jetty/BUCK
@@ -60,6 +60,18 @@
 )
 
 maven_jar(
+  name = 'jmx',
+  id = 'org.eclipse.jetty:jetty-jmx:' + VERSION,
+  sha1 = 'eb1492a8c6362410f84c97907b2ffb94c4dfcc2f',
+  license = 'Apache2.0',
+  exported_deps = [
+    ':continuation',
+    ':http',
+  ],
+  exclude = EXCLUDE,
+)
+
+maven_jar(
   name = 'continuation',
   id = 'org.eclipse.jetty:jetty-continuation:' + VERSION,
   sha1 = '5751f7ea38488dd32180bd3273f7f8591928aee3',
diff --git a/lib/jgit/BUCK b/lib/jgit/BUCK
index 80924d9..85d6d77 100644
--- a/lib/jgit/BUCK
+++ b/lib/jgit/BUCK
@@ -1,13 +1,13 @@
 include_defs('//lib/maven.defs')
 
-REPO = MAVEN_CENTRAL
-VERS = '3.3.0.201403021825-r'
+REPO = GERRIT
+VERS = '3.3.1.201403241930-r.80-gd5110c3'
 
 maven_jar(
   name = 'jgit',
   id = 'org.eclipse.jgit:org.eclipse.jgit:' + VERS,
-  bin_sha1 = '01aa346a5040bd541502dfb40e83edb1d1981c67',
-  src_sha1 = 'c27cc089751cc90dbe085ef09dd0c4a2acdb69cf',
+  bin_sha1 = 'fe38387f8a5079d660aad075cc80cfa39d269c38',
+  src_sha1 = '37196e15fa8e348c5073f7469da294e5285f05d9',
   license = 'jgit',
   repository = REPO,
   unsign = True,
@@ -22,7 +22,7 @@
 maven_jar(
   name = 'jgit-servlet',
   id = 'org.eclipse.jgit:org.eclipse.jgit.http.server:' + VERS,
-  sha1 = 'e141488647b80ef25d8d3febffd434a5e2a0a817',
+  sha1 = 'f0d8a1e8abca55a5723fbd595dd63992f16dea5a',
   license = 'jgit',
   repository = REPO,
   deps = [':jgit'],
@@ -36,7 +36,7 @@
 maven_jar(
   name = 'jgit-archive',
   id = 'org.eclipse.jgit:org.eclipse.jgit.archive:' + VERS,
-  sha1 = '87b2b50eb6e7a18a70fd684cc173f3bd2d8e24e8',
+  sha1 = 'e2938053672294e05ee540dcdb7fe57b4b7d6303',
   license = 'jgit',
   repository = REPO,
   deps = [':jgit',
@@ -53,7 +53,7 @@
 maven_jar(
   name = 'junit',
   id = 'org.eclipse.jgit:org.eclipse.jgit.junit:' + VERS,
-  sha1 = '13d0303a669bc2c44db69f8581e3634412b70eed',
+  sha1 = 'd9806c9bc9dac5c8f12f5c5b2b48f390c992ce32',
   license = 'DO_NOT_DISTRIBUTE',
   repository = REPO,
   unsign = True,
diff --git a/lib/mina/BUCK b/lib/mina/BUCK
index a3577c2..95e4761 100644
--- a/lib/mina/BUCK
+++ b/lib/mina/BUCK
@@ -8,8 +8,8 @@
 
 maven_jar(
   name = 'sshd',
-  id = 'org.apache.sshd:sshd-core:0.10.1',
-  sha1 = '0081c09917f35565d762c886758dfbdfa1069679',
+  id = 'org.apache.sshd:sshd-core:0.11.0',
+  sha1 = '450da44553c98805ca6bb5709cad54df4acb802a',
   license = 'Apache2.0',
   deps = [':core'],
   exclude = EXCLUDE,
diff --git a/plugins/BUCK b/plugins/BUCK
index 16c65da..480cd4c 100644
--- a/plugins/BUCK
+++ b/plugins/BUCK
@@ -4,6 +4,7 @@
   'download-commands',
   'replication',
   'reviewnotes',
+  'singleusergroup'
 ]
 
 # buck audit parses and resolves all deps even if not reachable
diff --git a/plugins/reviewnotes b/plugins/reviewnotes
index b544447..6170241 160000
--- a/plugins/reviewnotes
+++ b/plugins/reviewnotes
@@ -1 +1 @@
-Subproject commit b544447649d9ee3b3f78a6a1a7f839cb6a361292
+Subproject commit 61702414c046dd6b811c9137b765f9db422f83db
diff --git a/tools/buck.defs b/tools/buck.defs
deleted file mode 100644
index 8bcacc3..0000000
--- a/tools/buck.defs
+++ /dev/null
@@ -1,65 +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.
-
-original_java_library = java_library
-def java_library(
-    name,
-    srcs=[],
-    resources=[],
-    source='7',
-    target='7',
-    proguard_config=None,
-    deps=[],
-    exported_deps=[],
-    visibility=[],
-    ):
-  original_java_library(
-    name=name,
-    srcs=srcs,
-    resources=resources,
-    source=source,
-    target=target,
-    proguard_config=proguard_config,
-    deps=deps,
-    exported_deps=exported_deps,
-    visibility=visibility,
-  )
-
-original_java_test = java_test
-def java_test(
-    name,
-    srcs=[],
-    labels=[],
-    resources=[],
-    source='7',
-    target='7',
-    vm_args=[],
-    source_under_test=[],
-    contacts=[],
-    deps=[],
-    visibility=[],
-    ):
-  original_java_test(
-    name=name,
-    srcs=srcs,
-    labels=labels,
-    resources=resources,
-    source=source,
-    target=target,
-    vm_args=vm_args,
-    source_under_test=source_under_test,
-    contacts=contacts,
-    deps=deps,
-    visibility=visibility,
-  )
diff --git a/tools/default.defs b/tools/default.defs
index fa29908..fcc8d99 100644
--- a/tools/default.defs
+++ b/tools/default.defs
@@ -14,7 +14,6 @@
 
 # Rule definitions loaded by default into every BUCK file.
 
-include_defs('//tools/buck.defs')
 include_defs('//tools/gwt-constants.defs')
 
 def genantlr(
diff --git a/tools/download_file.py b/tools/download_file.py
index 3e6fca9..d4ddf1c 100755
--- a/tools/download_file.py
+++ b/tools/download_file.py
@@ -77,7 +77,7 @@
   if args.v:
     h = args.v
   else:
-    h = sha1(args.u).hexdigest()
+    h = sha1(args.u.encode('utf-8')).hexdigest()
   name = '%s-%s' % (path.basename(args.o), h)
   return path.join(CACHE_DIR, name)
 
diff --git a/tools/gwt-constants.defs b/tools/gwt-constants.defs
index 75c7503..b5f6292 100644
--- a/tools/gwt-constants.defs
+++ b/tools/gwt-constants.defs
@@ -7,6 +7,7 @@
 ]
 
 GWT_PLUGIN_DEPS = [
+  '//gerrit-gwtui-common:client',
   '//gerrit-plugin-gwtui:gwtui-api-lib',
   '//lib/gwt:user',
 ]