Merge "Add 'parentproject' operator that includes changes of child projects"
diff --git a/.buckversion b/.buckversion
index 62fc368..e39bcf8 100644
--- a/.buckversion
+++ b/.buckversion
@@ -1 +1 @@
-3fd3ea153c5444df2376de8ee87594a52a45bf52
+274acb17e9b6dc9ee60bc1371c47a7f49640c24c
diff --git a/.gitmodules b/.gitmodules
index 24cff1a..d75c98c 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,20 +1,23 @@
 [submodule "plugins/commit-message-length-validator"]
 	path = plugins/commit-message-length-validator
-	url = https://gerrit.googlesource.com/plugins/commit-message-length-validator
+	url = ../plugins/commit-message-length-validator
 
 [submodule "plugins/cookbook-plugin"]
 	path = plugins/cookbook-plugin
-	url = https://gerrit.googlesource.com/plugins/cookbook-plugin
+	url = ../plugins/cookbook-plugin
 
 [submodule "plugins/download-commands"]
 	path = plugins/download-commands
-	url = https://gerrit.googlesource.com/plugins/download-commands
+	url = ../plugins/download-commands
 
 [submodule "plugins/replication"]
 	path = plugins/replication
-	url = https://gerrit.googlesource.com/plugins/replication
+	url = ../plugins/replication
 
 [submodule "plugins/reviewnotes"]
 	path = plugins/reviewnotes
-	url = https://gerrit.googlesource.com/plugins/reviewnotes
+	url = ../plugins/reviewnotes
 
+[submodule "plugins/singleusergroup"]
+	path = plugins/singleusergroup
+	url = ../plugins/singleusergroup
diff --git a/BUCK b/BUCK
index 3d1541c..c78bc2c 100644
--- a/BUCK
+++ b/BUCK
@@ -11,6 +11,8 @@
   ':extension-api-src',
   ':plugin-api',
   ':plugin-api-src',
+  ':plugin-gwtui',
+  ':plugin-gwtui-src',
 ]
 
 genrule(
@@ -76,3 +78,19 @@
   ] + [d + '-src' for d in PLUGIN_API],
   visibility = ['//tools/maven:'],
 )
+
+genrule(
+  name = 'plugin-gwtui',
+  cmd = 'ln -s $(location //gerrit-plugin-gwtui:client) $OUT',
+  deps = ['//gerrit-plugin-gwtui:client'],
+  out = 'plugin-gwtui.jar',
+  visibility = ['//tools/maven:'],
+)
+
+genrule(
+  name = 'plugin-gwtui-src',
+  cmd = 'ln -s $(location //gerrit-plugin-gwtui:src) $OUT',
+  deps = ['//gerrit-plugin-gwtui:src'],
+  out = 'plugin-gwtui-src.jar',
+  visibility = ['//tools/maven:'],
+)
diff --git a/Documentation/access-control.txt b/Documentation/access-control.txt
index db806cc..f8d4308 100644
--- a/Documentation/access-control.txt
+++ b/Documentation/access-control.txt
@@ -425,7 +425,7 @@
 
 
 [[category_create]]
-Create reference
+Create Reference
 ~~~~~~~~~~~~~~~~
 
 The create reference category controls whether it is possible to
@@ -822,6 +822,10 @@
 can always edit the topic name (even without having the `Edit Topic Name`
 access right assigned).
 
+Whether the topic can be edited on closed changes can be controlled
+by the 'Force Edit' flag. If this flag is not set the topic can only be
+edited on open changes.
+
 
 Examples of typical roles in a project
 --------------------------------------
@@ -1336,3 +1340,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-apropos.txt b/Documentation/cmd-apropos.txt
index a24548d..29ce9fa 100644
--- a/Documentation/cmd-apropos.txt
+++ b/Documentation/cmd-apropos.txt
@@ -61,3 +61,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-ban-commit.txt b/Documentation/cmd-ban-commit.txt
index fb4a2ac9..fcdad5c 100644
--- a/Documentation/cmd-ban-commit.txt
+++ b/Documentation/cmd-ban-commit.txt
@@ -58,3 +58,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-cherry-pick.txt b/Documentation/cmd-cherry-pick.txt
index 15a8524..1275d20ea 100644
--- a/Documentation/cmd-cherry-pick.txt
+++ b/Documentation/cmd-cherry-pick.txt
@@ -45,3 +45,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-create-account.txt b/Documentation/cmd-create-account.txt
index 3ecb764..f22b4df 100644
--- a/Documentation/cmd-create-account.txt
+++ b/Documentation/cmd-create-account.txt
@@ -81,3 +81,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-create-group.txt b/Documentation/cmd-create-group.txt
index 8dc6dcc..1102a6d 100644
--- a/Documentation/cmd-create-group.txt
+++ b/Documentation/cmd-create-group.txt
@@ -92,3 +92,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-create-project.txt b/Documentation/cmd-create-project.txt
index e3ad834..da7820f 100644
--- a/Documentation/cmd-create-project.txt
+++ b/Documentation/cmd-create-project.txt
@@ -201,3 +201,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-flush-caches.txt b/Documentation/cmd-flush-caches.txt
index bc6fac5..050b433 100644
--- a/Documentation/cmd-flush-caches.txt
+++ b/Documentation/cmd-flush-caches.txt
@@ -104,3 +104,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-gc.txt b/Documentation/cmd-gc.txt
index 07b899a..50710e2 100644
--- a/Documentation/cmd-gc.txt
+++ b/Documentation/cmd-gc.txt
@@ -70,3 +70,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-gsql.txt b/Documentation/cmd-gsql.txt
index 3c1fd31..4efbb2a 100644
--- a/Documentation/cmd-gsql.txt
+++ b/Documentation/cmd-gsql.txt
@@ -65,3 +65,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-hook-commit-msg.txt b/Documentation/cmd-hook-commit-msg.txt
index c0c1e6c..c3ad1ac 100644
--- a/Documentation/cmd-hook-commit-msg.txt
+++ b/Documentation/cmd-hook-commit-msg.txt
@@ -117,6 +117,7 @@
 
 GERRIT
 ------
-
-
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-index.txt b/Documentation/cmd-index.txt
index 650b0bb..a274dec 100644
--- a/Documentation/cmd-index.txt
+++ b/Documentation/cmd-index.txt
@@ -183,3 +183,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-kill.txt b/Documentation/cmd-kill.txt
index f09053e..94371f0 100644
--- a/Documentation/cmd-kill.txt
+++ b/Documentation/cmd-kill.txt
@@ -28,3 +28,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-ls-groups.txt b/Documentation/cmd-ls-groups.txt
index 17ebba1..0713947 100644
--- a/Documentation/cmd-ls-groups.txt
+++ b/Documentation/cmd-ls-groups.txt
@@ -156,3 +156,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-ls-members.txt b/Documentation/cmd-ls-members.txt
index 9814ff2..d5f127f 100644
--- a/Documentation/cmd-ls-members.txt
+++ b/Documentation/cmd-ls-members.txt
@@ -62,3 +62,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-ls-projects.txt b/Documentation/cmd-ls-projects.txt
index 26530bd..5cd416d1 100644
--- a/Documentation/cmd-ls-projects.txt
+++ b/Documentation/cmd-ls-projects.txt
@@ -154,3 +154,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-ls-user-refs.txt b/Documentation/cmd-ls-user-refs.txt
index 25a99d1..26a083c 100644
--- a/Documentation/cmd-ls-user-refs.txt
+++ b/Documentation/cmd-ls-user-refs.txt
@@ -53,3 +53,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-plugin-enable.txt b/Documentation/cmd-plugin-enable.txt
index da651ca..ad1736d 100644
--- a/Documentation/cmd-plugin-enable.txt
+++ b/Documentation/cmd-plugin-enable.txt
@@ -42,3 +42,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-plugin-install.txt b/Documentation/cmd-plugin-install.txt
index 719c2bc..61663a6 100644
--- a/Documentation/cmd-plugin-install.txt
+++ b/Documentation/cmd-plugin-install.txt
@@ -71,3 +71,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-plugin-ls.txt b/Documentation/cmd-plugin-ls.txt
index 6cce83c..5e651b7 100644
--- a/Documentation/cmd-plugin-ls.txt
+++ b/Documentation/cmd-plugin-ls.txt
@@ -42,3 +42,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-plugin-reload.txt b/Documentation/cmd-plugin-reload.txt
index 3932e30..a4490a8 100644
--- a/Documentation/cmd-plugin-reload.txt
+++ b/Documentation/cmd-plugin-reload.txt
@@ -46,3 +46,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-plugin-remove.txt b/Documentation/cmd-plugin-remove.txt
index ab8f95b..f9c0eea 100644
--- a/Documentation/cmd-plugin-remove.txt
+++ b/Documentation/cmd-plugin-remove.txt
@@ -43,3 +43,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-query.txt b/Documentation/cmd-query.txt
index f7a784f..249b7f9 100644
--- a/Documentation/cmd-query.txt
+++ b/Documentation/cmd-query.txt
@@ -160,3 +160,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-receive-pack.txt b/Documentation/cmd-receive-pack.txt
index 92bb65e..239d2f5 100644
--- a/Documentation/cmd-receive-pack.txt
+++ b/Documentation/cmd-receive-pack.txt
@@ -88,3 +88,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-rename-group.txt b/Documentation/cmd-rename-group.txt
index e810727..624ac9b 100644
--- a/Documentation/cmd-rename-group.txt
+++ b/Documentation/cmd-rename-group.txt
@@ -44,3 +44,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-review.txt b/Documentation/cmd-review.txt
index 70213da..3038ead 100644
--- a/Documentation/cmd-review.txt
+++ b/Documentation/cmd-review.txt
@@ -134,3 +134,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-set-account.txt b/Documentation/cmd-set-account.txt
index f9855cd..19eb468 100644
--- a/Documentation/cmd-set-account.txt
+++ b/Documentation/cmd-set-account.txt
@@ -94,3 +94,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-set-members.txt b/Documentation/cmd-set-members.txt
index 7524893..d7da2eb 100644
--- a/Documentation/cmd-set-members.txt
+++ b/Documentation/cmd-set-members.txt
@@ -80,3 +80,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-set-project-parent.txt b/Documentation/cmd-set-project-parent.txt
index 1e7e6c5..5664890 100644
--- a/Documentation/cmd-set-project-parent.txt
+++ b/Documentation/cmd-set-project-parent.txt
@@ -71,3 +71,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-set-project.txt b/Documentation/cmd-set-project.txt
index af20006..df694a0 100644
--- a/Documentation/cmd-set-project.txt
+++ b/Documentation/cmd-set-project.txt
@@ -117,3 +117,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-set-reviewers.txt b/Documentation/cmd-set-reviewers.txt
index 32fd35e..81b493d 100644
--- a/Documentation/cmd-set-reviewers.txt
+++ b/Documentation/cmd-set-reviewers.txt
@@ -87,3 +87,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-show-caches.txt b/Documentation/cmd-show-caches.txt
index d426508..8c64b05 100644
--- a/Documentation/cmd-show-caches.txt
+++ b/Documentation/cmd-show-caches.txt
@@ -83,3 +83,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-show-connections.txt b/Documentation/cmd-show-connections.txt
index ab9fadf..154e1c2 100644
--- a/Documentation/cmd-show-connections.txt
+++ b/Documentation/cmd-show-connections.txt
@@ -88,3 +88,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-show-queue.txt b/Documentation/cmd-show-queue.txt
index 4ab3097..7364d2d 100644
--- a/Documentation/cmd-show-queue.txt
+++ b/Documentation/cmd-show-queue.txt
@@ -90,3 +90,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-stream-events.txt b/Documentation/cmd-stream-events.txt
index 10689b6..746b3ea 100644
--- a/Documentation/cmd-stream-events.txt
+++ b/Documentation/cmd-stream-events.txt
@@ -52,6 +52,7 @@
 Note that any field may be missing in the JSON messages, so consumers of
 this JSON stream should deal with that appropriately.
 
+[[events]]
 Events
 ~~~~~~
 Patchset Created
@@ -171,3 +172,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-suexec.txt b/Documentation/cmd-suexec.txt
index 78fc361..7b128fa 100644
--- a/Documentation/cmd-suexec.txt
+++ b/Documentation/cmd-suexec.txt
@@ -67,3 +67,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-test-submit-rule.txt b/Documentation/cmd-test-submit-rule.txt
index ae68b80..466182c 100644
--- a/Documentation/cmd-test-submit-rule.txt
+++ b/Documentation/cmd-test-submit-rule.txt
@@ -66,3 +66,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-test-submit-type.txt b/Documentation/cmd-test-submit-type.txt
index f6d5fba..2b8790c 100644
--- a/Documentation/cmd-test-submit-type.txt
+++ b/Documentation/cmd-test-submit-type.txt
@@ -51,3 +51,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-version.txt b/Documentation/cmd-version.txt
index aa08848..806e28a 100644
--- a/Documentation/cmd-version.txt
+++ b/Documentation/cmd-version.txt
@@ -46,3 +46,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/config-auto-site-initialization.txt b/Documentation/config-auto-site-initialization.txt
index 4c204fd..6111d5d 100644
--- a/Documentation/config-auto-site-initialization.txt
+++ b/Documentation/config-auto-site-initialization.txt
@@ -80,3 +80,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/config-cla.txt b/Documentation/config-cla.txt
index 6404d4e..fa28e7b 100644
--- a/Documentation/config-cla.txt
+++ b/Documentation/config-cla.txt
@@ -80,3 +80,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/config-contact.txt b/Documentation/config-contact.txt
index 4d8851f..6c59d2a 100644
--- a/Documentation/config-contact.txt
+++ b/Documentation/config-contact.txt
@@ -213,3 +213,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 814472a..1ceb3dc 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -1372,7 +1372,7 @@
 [[gerrit.changeScreen]]gerrit.changeScreen::
 +
 Default change screen UI to direct users to. Valid values are
-`OLD_UI` and `CHANGE_SCREEN2`. Default is `OLD_UI`.
+`OLD_UI` and `CHANGE_SCREEN2`. Default is `CHANGE_SCREEN2`.
 
 [[gitweb]]Section gitweb
 ~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2507,6 +2507,14 @@
 [[sshd]] Section sshd
 ~~~~~~~~~~~~~~~~~~~~~
 
+[[sshd.backend]]sshd.backend::
++
+Starting from version 0.9.0 Apache SSHD project added support for NIO2
+IoSession. To use the new NIO2 session the `backend` option must be set
+to `NIO2`.
++
+By default, `MINA`.
+
 [[sshd.listenAddress]]sshd.listenAddress::
 +
 Specifies the local addresses the internal SSHD should listen
@@ -2545,20 +2553,13 @@
 +
 By default, sshd.listenAddress.
 
-[[sshd.reuseAddress]]sshd.reuseAddress::
-+
-If true, permits the daemon to bind to the port even if the port
-is already in use.  If false, the daemon ensures the port is not
-in use before starting.  Busy sites may need to set this to true
-to permit fast restarts.
-+
-By default, true.
-
 [[sshd.tcpKeepAlive]]sshd.tcpKeepAlive::
 +
 If true, enables TCP keepalive messages to the other side, so
 the daemon can terminate connections if the peer disappears.
 +
+Only effective when `sshd.backend` is set to `MINA`.
++
 By default, true.
 
 [[sshd.threads]]sshd.threads::
@@ -3030,3 +3031,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/config-gitweb.txt b/Documentation/config-gitweb.txt
index 711174f..3e9cb96 100644
--- a/Documentation/config-gitweb.txt
+++ b/Documentation/config-gitweb.txt
@@ -282,3 +282,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/config-hooks.txt b/Documentation/config-hooks.txt
index e232c0c..f9a498b 100644
--- a/Documentation/config-hooks.txt
+++ b/Documentation/config-hooks.txt
@@ -126,7 +126,7 @@
 Called whenever a change's topic is changed from the Web UI or via the REST API.
 
 ====
-  topic-changed --change <change id> --changer <changer> --old-topic <old topic> --new-topic <new topic>
+  topic-changed --change <change id> --project <project name> --branch <branch> --changer <changer> --old-topic <old topic> --new-topic <new topic>
 ====
 
 cla-signed
@@ -169,3 +169,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/config-labels.txt b/Documentation/config-labels.txt
index c08d484..ba3d482 100644
--- a/Documentation/config-labels.txt
+++ b/Documentation/config-labels.txt
@@ -315,3 +315,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/config-login-register.txt b/Documentation/config-login-register.txt
index 867f0d4..d3911d7 100644
--- a/Documentation/config-login-register.txt
+++ b/Documentation/config-login-register.txt
@@ -141,3 +141,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/config-mail.txt b/Documentation/config-mail.txt
index 3b8bffa..ca9253ee 100644
--- a/Documentation/config-mail.txt
+++ b/Documentation/config-mail.txt
@@ -211,3 +211,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/config-project-config.txt b/Documentation/config-project-config.txt
index 8529b67..3267c45 100644
--- a/Documentation/config-project-config.txt
+++ b/Documentation/config-project-config.txt
@@ -223,3 +223,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/config-reverseproxy.txt b/Documentation/config-reverseproxy.txt
index 064fe2e..563b322 100644
--- a/Documentation/config-reverseproxy.txt
+++ b/Documentation/config-reverseproxy.txt
@@ -147,3 +147,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/config-sso.txt b/Documentation/config-sso.txt
index e915ffb..1d8d2d6 100644
--- a/Documentation/config-sso.txt
+++ b/Documentation/config-sso.txt
@@ -179,3 +179,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/config-themes.txt b/Documentation/config-themes.txt
index c102381..5eb8094 100644
--- a/Documentation/config-themes.txt
+++ b/Documentation/config-themes.txt
@@ -140,3 +140,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/config-validation.txt b/Documentation/config-validation.txt
index 1b09d19..7ef646b 100644
--- a/Documentation/config-validation.txt
+++ b/Documentation/config-validation.txt
@@ -40,3 +40,6 @@
 ------
 Part of link:index.html[Gerrit Code Review]
 
+
+SEARCHBOX
+---------
diff --git a/Documentation/database-setup.txt b/Documentation/database-setup.txt
index 3800473..1f48f53 100644
--- a/Documentation/database-setup.txt
+++ b/Documentation/database-setup.txt
@@ -113,3 +113,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/dev-buck.txt b/Documentation/dev-buck.txt
index 15c145a..c2a4584 100644
--- a/Documentation/dev-buck.txt
+++ b/Documentation/dev-buck.txt
@@ -175,7 +175,7 @@
 To build a specific plugin:
 
 ----
-  buck build plugins/<name>
+  buck build plugins/<name>:<name>
 ----
 
 The output JAR file will be be placed in:
@@ -187,6 +187,22 @@
 Note that when building an individual plugin, the `core.zip` package
 is not regenerated.
 
+Additional plugins with BUCK files can be added to the build
+environment by cloning the source repository into the plugins
+subdirectory:
+
+----
+  git clone https://gerrit.googlesource.com/plugins/<name> plugins/<name>
+  echo /plugins/<name> >>.git/info/exclude
+----
+
+Additional plugin sources will be automatically added to Eclipse the
+next time project.py is run:
+
+----
+  tools/eclipse/project.py
+----
+
 
 [[documentation]]
 Documentation
@@ -374,3 +390,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/dev-contributing.txt b/Documentation/dev-contributing.txt
index edc072d..24fc266 100644
--- a/Documentation/dev-contributing.txt
+++ b/Documentation/dev-contributing.txt
@@ -288,3 +288,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/dev-design.txt b/Documentation/dev-design.txt
index 3cb58b1..06dd95d 100644
--- a/Documentation/dev-design.txt
+++ b/Documentation/dev-design.txt
@@ -739,3 +739,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/dev-eclipse.txt b/Documentation/dev-eclipse.txt
index d2fc8f0..eeee5a3 100644
--- a/Documentation/dev-eclipse.txt
+++ b/Documentation/dev-eclipse.txt
@@ -102,3 +102,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/dev-inspector.txt b/Documentation/dev-inspector.txt
index 485ad7b..14177f8 100644
--- a/Documentation/dev-inspector.txt
+++ b/Documentation/dev-inspector.txt
@@ -180,11 +180,8 @@
 "schk" is "com.google.gerrit.server.schema.SchemaVersionCheck@5e8cb9bd"
 "ds" is "com.google.gerrit.server.schema.DataSourceProvider@6b3592c"
 "m" is "com.google.gerrit.lifecycle.LifecycleManager@6f03b248"
-"q" is "com.google.gerrit.reviewdb.server.ReviewDb_Schema_GwtOrm$$23@56d3384d"
 "Shell" is "com.google.gerrit.pgm.shell.JythonShell@61644f2d"
-"x" is "com.google.gerrit.reviewdb.client.PatchLineComment@518acfa7"
-"z" is "com.google.gwtorm.jdbc.Database@668dfd9b"
-"db" is "com.google.gerrit.reviewdb.server.ReviewDb_Schema_GwtOrm$$23@6a3ccb09"
+"d" is "com.google.gerrit.pgm.Daemon@28a3f689"
 
 Welcome to the Gerrit Inspector
 Enter help() to see the above again, EOF to quit and stop Gerrit
@@ -300,3 +297,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/dev-plugins.txt b/Documentation/dev-plugins.txt
index 8daacad..d1c79ac 100644
--- a/Documentation/dev-plugins.txt
+++ b/Documentation/dev-plugins.txt
@@ -346,6 +346,12 @@
 notifications of these events by implementing the corresponding
 listeners.
 
+* `com.google.gerrit.common.ChangeListener`:
++
+Allows to listen to change events. These are the same
+link:cmd-stream-events.html#events[events] that are also streamed by
+the link:cmd-stream-events.html[gerrit stream-events] command.
+
 * `com.google.gerrit.extensions.events.LifecycleListener`:
 +
 Gerrit server startup and shutdown
@@ -381,7 +387,9 @@
 [source,java]
 ----
 import com.google.gerrit.sshd.SshCommand;
+import com.google.gerrit.sshd.CommandMetaData;
 
+@CommandMetaData(name="print", descr="Print hello command")
 class PrintHello extends SshCommand {
   protected abstract void run() {
     stdout.print("Hello\n");
@@ -415,7 +423,7 @@
 
 class MyCommands extends PluginCommandModule {
   protected void configureCommands() {
-    command("print").to(PrintHello.class);
+    command(PrintHello.class);
   }
 }
 ----
@@ -465,9 +473,33 @@
 $ ssh -p 29418 review.example.com shell ps
 ----
 
-[[configuration]]
-Configuration
--------------
+Single command plugins are also supported. In this scenario plugin binds
+SSH command to its own name. `SshModule` must inherit from
+`SingleCommandPluginModule` class:
+
+[source,java]
+----
+public class SshModule extends SingleCommandPluginModule {
+ @Override
+ protected void configure(LinkedBindingBuilder<Command> b) {
+    b.to(ShellCommand.class);
+  }
+}
+----
+
+If the plugin above is deployed under sh.jar file in `$site/plugins`
+directory, generic commands can be called without specifing the
+actual SSH command. Note in the example below, that the called commands
+`ls` and `ps` was not explicitly bound:
+
+----
+$ ssh -p 29418 review.example.com sh ls
+$ ssh -p 29418 review.example.com sh ps
+----
+
+[[simple-configuration]]
+Simple Configuration in `gerrit.config`
+---------------------------------------
 
 In Gerrit, global configuration is stored in the `gerrit.config` file.
 If a plugin needs global configuration, this configuration should be
@@ -477,12 +509,12 @@
 plugins that have a simple configuration that only consists of
 key-value pairs. With this approach it is not possible to have
 subsections in the plugin configuration. Plugins that require a complex
-configuration need to store their configuration in their own
-configuration file where they can make use of subsections. On the other
-hand storing the plugin configuration in a 'plugin' subsection in the
-`gerrit.config` file has the advantage that administrators have all
-configuration parameters in one file, instead of having one
-configuration file per plugin.
+configuration need to store their configuration in their
+link:#configuration[own configuration file] where they can make use of
+subsections. On the other hand storing the plugin configuration in a
+'plugin' subsection in the `gerrit.config` file has the advantage that
+administrators have all configuration parameters in one file, instead
+of having one configuration file per plugin.
 
 To avoid conflicts with other plugins, it is recommended that plugins
 only use the `plugin` subsection with their own name. For example the
@@ -509,9 +541,52 @@
                      .getString("language", "English");
 ----
 
-[[project-specific-configuration]]
-Project Specific Configuration
-------------------------------
+[[configuration]]
+Configuration in own config file
+--------------------------------
+
+Plugins can store their configuration in an own configuration file.
+This makes sense if the plugin configuration is rather complex and
+requires the usage of subsections. Plugins that have a simple
+key-value pair configuration can store their configuration in a
+link:#simple-configuration[`plugin` subsection of the `gerrit.config`
+file].
+
+The plugin configuration file must be named after the plugin and must
+be located in the `etc` folder of the review site. For example a
+configuration file for a `default-reviewer` plugin could look like
+this:
+
+.$site_path/etc/default-reviewer.config
+----
+[branch "refs/heads/master"]
+  reviewer = Project Owners
+  reviewer = john.doe@example.com
+[match "file:^.*\.txt"]
+  reviewer = My Info Developers
+----
+
+Via the `com.google.gerrit.server.config.PluginConfigFactory` class a
+plugin can easily access its configuration:
+
+[source,java]
+----
+@Inject
+private com.google.gerrit.server.config.PluginConfigFactory cfg;
+
+[...]
+
+String[] reviewers = cfg.getGlobalPluginConfig("default-reviewer")
+                        .getStringList("branch", "refs/heads/master", "reviewer");
+----
+
+The plugin configuration is loaded only once and is then cached.
+Similar to changes in 'gerrit.config', changes to the plugin
+configuration file will only become effective after a Gerrit restart.
+
+[[simple-project-specific-configuration]]
+Simple Project Specific Configuration in `project.config`
+---------------------------------------------------------
 
 In Gerrit, project specific configuration is stored in the project's
 `project.config` file on the `refs/meta/config` branch.  If a plugin
@@ -523,12 +598,12 @@
 plugins that have a simple configuration that only consists of
 key-value pairs. With this approach it is not possible to have
 subsections in the plugin configuration. Plugins that require a complex
-configuration need to store their configuration in their own
-configuration file where they can make use of subsections. On the other
-hand storing the plugin configuration in a 'plugin' subsection in the
-`project.config` file has the advantage that project owners have all
-configuration parameters in one file, instead of having one
-configuration file per plugin.
+configuration need to store their configuration in their
+link:#project-specific-configuration[own configuration file] where they
+can make use of subsections. On the other hand storing the plugin
+configuration in a 'plugin' subsection in the `project.config` file has
+the advantage that project owners have all configuration parameters in
+one file, instead of having one configuration file per plugin.
 
 To avoid conflicts with other plugins, it is recommended that plugins
 only use the `plugin` subsection with their own name. For example the
@@ -573,6 +648,63 @@
 `refs/meta/config` branch, editing the `project.config` file and
 pushing the commit back.
 
+[[project-specific-configuration]]
+Project Specific Configuration in own config file
+-------------------------------------------------
+
+Plugins can store their project specific configuration in an own
+configuration file in the projects `refs/meta/config` branch.
+This makes sense if the plugins project specific configuration is
+rather complex and requires the usage of subsections. Plugins that
+have a simple key-value pair configuration can store their project
+specific configuration in a link:#simple-project-specific-configuration[
+`plugin` subsection of the `project.config` file].
+
+The plugin configuration file in the `refs/meta/config` branch must be
+named after the plugin. For example a configuration file for a
+`default-reviewer` plugin could look like this:
+
+.default-reviewer.config
+----
+[branch "refs/heads/master"]
+  reviewer = Project Owners
+  reviewer = john.doe@example.com
+[match "file:^.*\.txt"]
+  reviewer = My Info Developers
+----
+
+Via the `com.google.gerrit.server.config.PluginConfigFactory` class a
+plugin can easily access its project specific configuration:
+
+[source,java]
+----
+@Inject
+private com.google.gerrit.server.config.PluginConfigFactory cfg;
+
+[...]
+
+String[] reviewers = cfg.getProjectPluginConfig(project, "default-reviewer")
+                        .getStringList("branch", "refs/heads/master", "reviewer");
+----
+
+It is also possible to get missing configuration parameters inherited
+from the parent projects:
+
+[source,java]
+----
+@Inject
+private com.google.gerrit.server.config.PluginConfigFactory cfg;
+
+[...]
+
+String[] reviewers = cfg.getFromPluginConfigWithInheritance(project, "default-reviewer")
+                        .getStringList("branch", "refs/heads/master", "reviewer");
+----
+
+Project owners can edit the project configuration by fetching the
+`refs/meta/config` branch, editing the `<plugin-name>.config` file and
+pushing the commit back.
+
 [[capabilities]]
 Plugin Owned Capabilities
 -------------------------
@@ -667,16 +799,17 @@
 UI Extension
 ------------
 
-Plugins can contribute their own UI actions on core Gerrit pages.
-This is useful for workflow customization or exposing plugin functionality
-through the UI in addition to SSH commands and the REST API.
+Plugins can contribute UI actions on core Gerrit pages. This is useful
+for workflow customization or exposing plugin functionality through the
+UI in addition to SSH commands and the REST API.
 
-For instance a plugin to integrate Jira with Gerrit changes may contribute its
-own "File bug" button to allow filing a bug from the change page or plugins to
-integrate continuous integration systems may contribute a "Schedule" button to
-allow a CI build to be scheduled manually from the patch set panel.
+For instance a plugin to integrate Jira with Gerrit changes may
+contribute a "File bug" button to allow filing a bug from the change
+page or plugins to integrate continuous integration systems may
+contribute a "Schedule" button to allow a CI build to be scheduled
+manually from the patch set panel.
 
-Two different places on core Gerrit pages are currently supported:
+Two different places on core Gerrit pages are supported:
 
 * Change screen
 * Project info screen
@@ -785,7 +918,8 @@
 }
 ----
 
-The module above must be declared in pom.xml for Maven driven plugins:
+The module above must be declared in the `pom.xml` for Maven driven
+plugins:
 
 [source,xml]
 ----
@@ -794,7 +928,7 @@
 </manifestEntries>
 ----
 
-or in the BUCK configuration file for Buck driven plugins:
+or in the `BUCK` configuration file for Buck driven plugins:
 
 [source,python]
 ----
@@ -849,7 +983,8 @@
 }
 ----
 
-The HTTP module above must be declared in pom.xml for Maven driven plugins:
+The HTTP module above must be declared in the `pom.xml` for Maven
+driven plugins:
 
 [source,xml]
 ----
@@ -858,7 +993,7 @@
 </manifestEntries>
 ----
 
-or in the BUCK configuration file for Buck driven plugins
+or in the `BUCK` configuration file for Buck driven plugins
 
 [source,python]
 ----
@@ -875,7 +1010,7 @@
 The following prerequisities must be met, to satisfy the capability check:
 
 * user is authenticated
-* user is a member of the Administrators group, or
+* user is a member of a group which has the `Administrate Server` capability, or
 * user is a member of a group which has the required capability
 
 The `apply` method is called when the button is clicked. If `UiAction` is
@@ -895,7 +1030,7 @@
 ====
 
 A special case is to bind an endpoint without a view name.  This is
-particularly useful for DELETE requests:
+particularly useful for `DELETE` requests:
 
 [source,java]
 ----
@@ -1002,6 +1137,303 @@
 Gerrit-Module: com.googlesource.gerrit.plugins.helloworld.HelloWorldModule
 ----
 
+It is also possible to show some menu entries only if the user has a
+certain capability:
+
+[source,java]
+----
+public class MyTopMenuExtension implements TopMenu {
+  private final String pluginName;
+  private final Provider<CurrentUser> userProvider;
+  private final List<MenuEntry> menuEntries;
+
+  @Inject
+  public MyTopMenuExtension(@PluginName String pluginName,
+      Provider<CurrentUser> userProvider) {
+    this.pluginName = pluginName;
+    this.userProvider = userProvider;
+    menuEntries = new ArrayList<TopMenu.MenuEntry>();
+
+    // add menu entry that is only visible to users with a certain capability
+    if (canSeeMenuEntry()) {
+      menuEntries.add(new MenuEntry("Top Menu Entry", Collections
+          .singletonList(new MenuItem("Gerrit", "http://gerrit.googlecode.com/"))));
+    }
+
+    // add menu entry that is visible to all users (even anonymous users)
+    menuEntries.add(new MenuEntry("Top Menu Entry", Collections
+          .singletonList(new MenuItem("Documentation", "/plugins/myplugin/"))));
+  }
+
+  private boolean canSeeMenuEntry() {
+    if (userProvider.get().isIdentifiedUser()) {
+      CapabilityControl ctl = userProvider.get().getCapabilities();
+      return ctl.canPerform(pluginName + "-" + MyCapability.ID)
+          || ctl.canAdministrateServer();
+    } else {
+      return false;
+    }
+  }
+
+  @Override
+  public List<MenuEntry> getEntries() {
+    return menuEntries;
+  }
+}
+----
+
+[[gwt_ui_extension]]
+GWT UI Extension
+----------------
+Plugins can extend the Gerrit UI with own GWT code.
+
+The Maven archetype 'gerrit-plugin-gwt-archetype' can be used to
+generate a GWT plugin skeleton. How to use the Maven plugin archetypes
+is described in the link:#getting-started[Getting started] section.
+
+The generated GWT plugin has a link:#top-menu-extensions[top menu] that
+opens a GWT dialog box when the user clicks on it.
+
+In addition to the Gerrit-Plugin API a GWT plugin depends on
+`gerrit-plugin-gwtui`. This dependency must be specified in the
+`pom.xml`:
+
+[source,xml]
+----
+<dependency>
+  <groupId>com.google.gerrit</groupId>
+  <artifactId>gerrit-plugin-gwtui</artifactId>
+  <version>${Gerrit-ApiVersion}</version>
+</dependency>
+----
+
+A GWT plugin must contain a GWT module file, e.g. `HelloPlugin.gwt.xml`,
+that bundles together all the configuration settings of the GWT plugin:
+
+[source,xml]
+----
+<?xml version="1.0" encoding="UTF-8"?>
+<module rename-to="hello_gwt_plugin">
+  <!-- Inherit the core Web Toolkit stuff. -->
+  <inherits name="com.google.gwt.user.User"/>
+  <!-- Other module inherits -->
+  <inherits name="com.google.gerrit.Plugin"/>
+  <inherits name="com.google.gwt.http.HTTP"/>
+  <!-- Using GWT built-in themes adds a number of static -->
+  <!-- resources to the plugin. No theme inherits lines were -->
+  <!-- added in order to make this plugin as simple as possible -->
+  <!-- Specify the app entry point class. -->
+  <entry-point class="${package}.client.HelloPlugin"/>
+  <stylesheet src="hello.css"/>
+</module>
+----
+
+The GWT module must inherit `com.google.gerrit.Plugin` and
+`com.google.gwt.http.HTTP`.
+
+To register the GWT module a `GwtPlugin` needs to be bound.
+
+If no Guice modules are declared in the manifest, the GWT plugin may
+use auto-registration by using the `@Listen` annotation:
+
+[source,java]
+----
+@Listen
+public class MyExtension extends GwtPlugin {
+  public MyExtension() {
+    super("hello_gwt_plugin");
+  }
+}
+----
+
+Otherwise the binding must be done in an `HttpModule`:
+
+[source,java]
+----
+public class HttpModule extends HttpPluginModule {
+
+  @Override
+  protected void configureServlets() {
+    DynamicSet.bind(binder(), WebUiPlugin.class)
+        .toInstance(new GwtPlugin("hello_gwt_plugin"));
+  }
+}
+----
+
+The HTTP module above must be declared in the `pom.xml` for Maven
+driven plugins:
+
+[source,xml]
+----
+<manifestEntries>
+  <Gerrit-HttpModule>com.googlesource.gerrit.plugins.myplugin.HttpModule</Gerrit-HttpModule>
+</manifestEntries>
+----
+
+It is important that the module name that is provided to the
+`GwtPlugin` matches the GWT module contained in the plugin. The name
+of the GWT module can be explicitly set in the GWT module file by
+specifying the `rename-to` attribute on the module.
+
+[source,xml]
+----
+<module rename-to="hello_gwt_plugin">
+----
+
+The actual GWT code must be implemented in a class that extends
+`com.google.gerrit.plugin.client.Plugin`:
+
+[source,java]
+----
+public class HelloPlugin extends Plugin {
+
+  @Override
+  public void onModuleLoad() {
+    // Create the dialog box
+    final DialogBox dialogBox = new DialogBox();
+
+    // The content of the dialog comes from a User specified Preference
+    dialogBox.setText("Hello from GWT Gerrit UI plugin");
+    dialogBox.setAnimationEnabled(true);
+    Button closeButton = new Button("Close");
+    VerticalPanel dialogVPanel = new VerticalPanel();
+    dialogVPanel.setWidth("100%");
+    dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_CENTER);
+    dialogVPanel.add(closeButton);
+
+    closeButton.addClickHandler(new ClickHandler() {
+      public void onClick(ClickEvent event) {
+        dialogBox.hide();
+      }
+    });
+
+    // Set the contents of the Widget
+    dialogBox.setWidget(dialogVPanel);
+
+    RootPanel rootPanel = RootPanel.get(HelloMenu.MENU_ID);
+    rootPanel.getElement().removeAttribute("href");
+    rootPanel.addDomHandler(new ClickHandler() {
+        @Override
+        public void onClick(ClickEvent event) {
+          dialogBox.center();
+          dialogBox.show();
+        }
+    }, ClickEvent.getType());
+  }
+}
+----
+
+This class must be set as entry point in the GWT module:
+
+[source,xml]
+----
+<entry-point class="${package}.client.HelloPlugin"/>
+----
+
+In addition this class must be defined as module in the `pom.xml` for the
+`gwt-maven-plugin` and the `webappDirectory` option of `gwt-maven-plugin`
+must be set to `${project.build.directory}/classes/static`:
+
+[source,xml]
+----
+<plugin>
+  <groupId>org.codehaus.mojo</groupId>
+  <artifactId>gwt-maven-plugin</artifactId>
+  <version>2.5.1</version>
+  <configuration>
+    <module>com.googlesource.gerrit.plugins.myplugin.HelloPlugin</module>
+    <disableClassMetadata>true</disableClassMetadata>
+    <disableCastChecking>true</disableCastChecking>
+    <webappDirectory>${project.build.directory}/classes/static</webappDirectory>
+  </configuration>
+  <executions>
+    <execution>
+      <goals>
+        <goal>compile</goal>
+      </goals>
+    </execution>
+  </executions>
+</plugin>
+----
+
+To attach a GWT widget defined by the plugin to the Gerrit core UI
+`com.google.gwt.user.client.ui.RootPanel` can be used to manipulate the
+Gerrit core widgets:
+
+[source,java]
+----
+RootPanel rootPanel = RootPanel.get(HelloMenu.MENU_ID);
+rootPanel.getElement().removeAttribute("href");
+rootPanel.addDomHandler(new ClickHandler() {
+  @Override
+  public void onClick(ClickEvent event) {
+    dialogBox.center();
+    dialogBox.show();
+  }
+}, ClickEvent.getType());
+----
+
+GWT plugins can come with their own css file. This css file must have a
+unique name and must be registered in the GWT module:
+
+[source,xml]
+----
+<stylesheet src="hello.css"/>
+----
+
+If a GWT plugin wants to invoke the Gerrit REST API it can use
+`com.google.gerrit.plugin.client.rpc.RestApi` to contruct the URL
+path and to trigger the REST calls.
+
+Example for invoking a Gerrit core REST endpoint:
+
+[source,java]
+----
+new RestApi("projects").id(projectName).view("description")
+    .put("new description", new AsyncCallback<JavaScriptObject>() {
+
+  @Override
+  public void onSuccess(JavaScriptObject result) {
+    // TODO
+  }
+
+  @Override
+  public void onFailure(Throwable caught) {
+    // never invoked
+  }
+});
+----
+
+Example for invoking a REST endpoint defined by a plugin:
+
+[source,java]
+----
+new RestApi("projects").id(projectName).view("myplugin", "myview")
+    .get(new AsyncCallback<JavaScriptObject>() {
+
+  @Override
+  public void onSuccess(JavaScriptObject result) {
+    // TODO
+  }
+
+  @Override
+  public void onFailure(Throwable caught) {
+    // never invoked
+  }
+});
+----
+
+The `onFailure(Throwable)` of the provided callback is never invoked.
+If an error occurs, it is shown in an error dialog.
+
+In order to be able to do REST calls the GWT module must inherit
+`com.google.gwt.json.JSON`:
+
+[source,xml]
+----
+<inherits name="com.google.gwt.json.JSON"/>
+----
+
 [[http]]
 HTTP Servlets
 -------------
@@ -1211,3 +1643,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/dev-readme.txt b/Documentation/dev-readme.txt
index 728c8dc..d961f70 100644
--- a/Documentation/dev-readme.txt
+++ b/Documentation/dev-readme.txt
@@ -246,3 +246,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/dev-release-deploy-config.txt b/Documentation/dev-release-deploy-config.txt
index 9c98fff..6ea32b7 100644
--- a/Documentation/dev-release-deploy-config.txt
+++ b/Documentation/dev-release-deploy-config.txt
@@ -132,3 +132,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/dev-release-subproject.txt b/Documentation/dev-release-subproject.txt
index 956bd29..b9a39be 100644
--- a/Documentation/dev-release-subproject.txt
+++ b/Documentation/dev-release-subproject.txt
@@ -107,3 +107,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/dev-release.txt b/Documentation/dev-release.txt
index f9d0d0e..b9b9ff0 100644
--- a/Documentation/dev-release.txt
+++ b/Documentation/dev-release.txt
@@ -359,3 +359,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/dev-rest-api.txt b/Documentation/dev-rest-api.txt
index 0175a62..24b60f0 100644
--- a/Documentation/dev-rest-api.txt
+++ b/Documentation/dev-rest-api.txt
@@ -87,3 +87,5 @@
 ------
 Part of link:index.html[Gerrit Code Review]
 
+SEARCHBOX
+---------
diff --git a/Documentation/error-branch-not-found.txt b/Documentation/error-branch-not-found.txt
index bd8d090..a8b1741 100644
--- a/Documentation/error-branch-not-found.txt
+++ b/Documentation/error-branch-not-found.txt
@@ -32,3 +32,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-change-closed.txt b/Documentation/error-change-closed.txt
index 3244fb3..e466c2e 100644
--- a/Documentation/error-change-closed.txt
+++ b/Documentation/error-change-closed.txt
@@ -39,3 +39,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-change-does-not-belong-to-project.txt b/Documentation/error-change-does-not-belong-to-project.txt
index e747881..db16261 100644
--- a/Documentation/error-change-does-not-belong-to-project.txt
+++ b/Documentation/error-change-does-not-belong-to-project.txt
@@ -14,3 +14,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-change-not-found.txt b/Documentation/error-change-not-found.txt
index b6df13b..e578ef5 100644
--- a/Documentation/error-change-not-found.txt
+++ b/Documentation/error-change-not-found.txt
@@ -13,3 +13,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-change-upload-blocked.txt b/Documentation/error-change-upload-blocked.txt
index 6bad02e..3b413bd2 100644
--- a/Documentation/error-change-upload-blocked.txt
+++ b/Documentation/error-change-upload-blocked.txt
@@ -39,3 +39,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-commit-already-exists.txt b/Documentation/error-commit-already-exists.txt
index dc32c4c1..6a2170a 100644
--- a/Documentation/error-commit-already-exists.txt
+++ b/Documentation/error-commit-already-exists.txt
@@ -12,3 +12,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-contains-banned-commit.txt b/Documentation/error-contains-banned-commit.txt
index 8a30c44..f6ac30d 100644
--- a/Documentation/error-contains-banned-commit.txt
+++ b/Documentation/error-contains-banned-commit.txt
@@ -19,3 +19,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-has-duplicates.txt b/Documentation/error-has-duplicates.txt
index b5175c0..4eac779 100644
--- a/Documentation/error-has-duplicates.txt
+++ b/Documentation/error-has-duplicates.txt
@@ -22,3 +22,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-invalid-author.txt b/Documentation/error-invalid-author.txt
index c484776..7067cde 100644
--- a/Documentation/error-invalid-author.txt
+++ b/Documentation/error-invalid-author.txt
@@ -143,3 +143,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-invalid-changeid-line.txt b/Documentation/error-invalid-changeid-line.txt
index 9235266..a1d7f15 100644
--- a/Documentation/error-invalid-changeid-line.txt
+++ b/Documentation/error-invalid-changeid-line.txt
@@ -29,3 +29,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-invalid-committer.txt b/Documentation/error-invalid-committer.txt
index 447064e..e27961f 100644
--- a/Documentation/error-invalid-committer.txt
+++ b/Documentation/error-invalid-committer.txt
@@ -108,3 +108,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-messages.txt b/Documentation/error-messages.txt
index 58e9e02..18aa12a 100644
--- a/Documentation/error-messages.txt
+++ b/Documentation/error-messages.txt
@@ -47,3 +47,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-missing-changeid.txt b/Documentation/error-missing-changeid.txt
index edbc63b..833e6ac 100644
--- a/Documentation/error-missing-changeid.txt
+++ b/Documentation/error-missing-changeid.txt
@@ -70,3 +70,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-multiple-changeid-lines.txt b/Documentation/error-multiple-changeid-lines.txt
index 9fa2b91..9b094d4 100644
--- a/Documentation/error-multiple-changeid-lines.txt
+++ b/Documentation/error-multiple-changeid-lines.txt
@@ -29,3 +29,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-no-changes-made.txt b/Documentation/error-no-changes-made.txt
index d0e1d4f..4987b16 100644
--- a/Documentation/error-no-changes-made.txt
+++ b/Documentation/error-no-changes-made.txt
@@ -19,3 +19,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-no-common-ancestry.txt b/Documentation/error-no-common-ancestry.txt
index 615da71..174e52b 100644
--- a/Documentation/error-no-common-ancestry.txt
+++ b/Documentation/error-no-common-ancestry.txt
@@ -18,3 +18,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-no-new-changes.txt b/Documentation/error-no-new-changes.txt
index 8e409ef..20357a4 100644
--- a/Documentation/error-no-new-changes.txt
+++ b/Documentation/error-no-new-changes.txt
@@ -49,3 +49,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-non-fast-forward.txt b/Documentation/error-non-fast-forward.txt
index 6604e10..f9b2caa 100644
--- a/Documentation/error-non-fast-forward.txt
+++ b/Documentation/error-non-fast-forward.txt
@@ -57,3 +57,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-not-a-gerrit-administrator.txt b/Documentation/error-not-a-gerrit-administrator.txt
index b771af6..98dd64c 100644
--- a/Documentation/error-not-a-gerrit-administrator.txt
+++ b/Documentation/error-not-a-gerrit-administrator.txt
@@ -12,3 +12,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-not-allowed-to-upload-merges.txt b/Documentation/error-not-allowed-to-upload-merges.txt
index 515eef5..fd2f10c 100644
--- a/Documentation/error-not-allowed-to-upload-merges.txt
+++ b/Documentation/error-not-allowed-to-upload-merges.txt
@@ -19,3 +19,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-not-permitted-to-create.txt b/Documentation/error-not-permitted-to-create.txt
index 9c07fd1..f41b645 100644
--- a/Documentation/error-not-permitted-to-create.txt
+++ b/Documentation/error-not-permitted-to-create.txt
@@ -14,3 +14,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-not-signed-off-by.txt b/Documentation/error-not-signed-off-by.txt
index bd1f40d..a3d6bbd 100644
--- a/Documentation/error-not-signed-off-by.txt
+++ b/Documentation/error-not-signed-off-by.txt
@@ -29,3 +29,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-not-valid-ref.txt b/Documentation/error-not-valid-ref.txt
index 128e796..5bba8e6 100644
--- a/Documentation/error-not-valid-ref.txt
+++ b/Documentation/error-not-valid-ref.txt
@@ -44,3 +44,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-permission-denied.txt b/Documentation/error-permission-denied.txt
index 2ec0a3f..a97161f 100644
--- a/Documentation/error-permission-denied.txt
+++ b/Documentation/error-permission-denied.txt
@@ -60,3 +60,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-prohibited-by-gerrit.txt b/Documentation/error-prohibited-by-gerrit.txt
index bad2b3c..2a65ea2 100644
--- a/Documentation/error-prohibited-by-gerrit.txt
+++ b/Documentation/error-prohibited-by-gerrit.txt
@@ -39,3 +39,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-project-not-found.txt b/Documentation/error-project-not-found.txt
index 3fc0141..29af5f8 100644
--- a/Documentation/error-project-not-found.txt
+++ b/Documentation/error-project-not-found.txt
@@ -32,3 +32,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-push-fails-due-to-commit-message.txt b/Documentation/error-push-fails-due-to-commit-message.txt
index 172d64f..046789e 100644
--- a/Documentation/error-push-fails-due-to-commit-message.txt
+++ b/Documentation/error-push-fails-due-to-commit-message.txt
@@ -39,3 +39,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-squash-commits-first.txt b/Documentation/error-squash-commits-first.txt
index 2181c52..9434363 100644
--- a/Documentation/error-squash-commits-first.txt
+++ b/Documentation/error-squash-commits-first.txt
@@ -106,3 +106,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/error-upload-denied.txt b/Documentation/error-upload-denied.txt
index 5dec8ab..6de94b4 100644
--- a/Documentation/error-upload-denied.txt
+++ b/Documentation/error-upload-denied.txt
@@ -17,3 +17,6 @@
 GERRIT
 ------
 Part of link:error-messages.html[Gerrit Error Messages]
+
+SEARCHBOX
+---------
diff --git a/Documentation/i18n-readme.txt b/Documentation/i18n-readme.txt
index 2135598..46abaad 100644
--- a/Documentation/i18n-readme.txt
+++ b/Documentation/i18n-readme.txt
@@ -22,3 +22,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/images/intro-quick-central-gerrit.png b/Documentation/images/intro-quick-central-gerrit.png
index 61b9638..8717176 100644
--- a/Documentation/images/intro-quick-central-gerrit.png
+++ b/Documentation/images/intro-quick-central-gerrit.png
Binary files differ
diff --git a/Documentation/images/intro-quick-central-repo.png b/Documentation/images/intro-quick-central-repo.png
index 84ffeb0..8400b5e 100644
--- a/Documentation/images/intro-quick-central-repo.png
+++ b/Documentation/images/intro-quick-central-repo.png
Binary files differ
diff --git a/Documentation/index.txt b/Documentation/index.txt
index 9b8acc4..e696bfb 100644
--- a/Documentation/index.txt
+++ b/Documentation/index.txt
@@ -60,7 +60,7 @@
 ... How to read stats from the JVM
 .. High availability
 .. Replication
-.. Plugins
+.. link:https://gerrit-review.googlesource.com/#/admin/projects/?filter=plugins%252F[Plugins]
 .. link:dev-design.html[System Design]
 .. link:config-contact.html[User Contact Information]
 .. link:config-reverseproxy.html[Reverse Proxy]
@@ -91,3 +91,6 @@
 * link:http://code.google.com/p/gerrit/issues/list[Issue Tracking]
 * link:http://code.google.com/p/gerrit/source/checkout[Source Code]
 * link:http://code.google.com/p/gerrit/wiki/Background[A History of Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/install-j2ee.txt b/Documentation/install-j2ee.txt
index 5ba8cb1..dd9657c 100644
--- a/Documentation/install-j2ee.txt
+++ b/Documentation/install-j2ee.txt
@@ -117,3 +117,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/install-quick.txt b/Documentation/install-quick.txt
index f1bd25c..741de35 100644
--- a/Documentation/install-quick.txt
+++ b/Documentation/install-quick.txt
@@ -232,3 +232,6 @@
 ------
 
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/install.txt b/Documentation/install.txt
index 1d6d1bd..8e836f8 100644
--- a/Documentation/install.txt
+++ b/Documentation/install.txt
@@ -194,3 +194,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/intro-change-screen.txt b/Documentation/intro-change-screen.txt
index 2913336..80ac974 100644
--- a/Documentation/intro-change-screen.txt
+++ b/Documentation/intro-change-screen.txt
@@ -28,10 +28,10 @@
 Configuration
 -------------
 
-The new change screen is deactivated by default. It can be activated system-wide
-by changing the link:config-gerrit.html[gerrit.changeScreen] setting to
-`CHANGE_SCREEN2`.  Users can deactivate it by setting `OLD_UI` on their user
-preferences page.
+The new change screen is activated by default. It can be deactivated
+system-wide by changing the link:config-gerrit.html[gerrit.changeScreen]
+setting to `OLD_UI`.  Users can deactivate it by setting `OLD_UI` on their
+user preferences page.
 
 [[switching-between-patch-sets]]
 Switching between patch sets
@@ -214,3 +214,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/intro-quick.txt b/Documentation/intro-quick.txt
index ae2e7e7..cd3374b 100644
--- a/Documentation/intro-quick.txt
+++ b/Documentation/intro-quick.txt
@@ -390,3 +390,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/js-api.txt b/Documentation/js-api.txt
index 2e97ac4..0e470e7 100644
--- a/Documentation/js-api.txt
+++ b/Documentation/js-api.txt
@@ -636,3 +636,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/json.txt b/Documentation/json.txt
index 9278cde..73dbd92 100644
--- a/Documentation/json.txt
+++ b/Documentation/json.txt
@@ -276,3 +276,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/pgm-LocalUsernamesToLowerCase.txt b/Documentation/pgm-LocalUsernamesToLowerCase.txt
index 9189fee..f1d21f89 100644
--- a/Documentation/pgm-LocalUsernamesToLowerCase.txt
+++ b/Documentation/pgm-LocalUsernamesToLowerCase.txt
@@ -66,3 +66,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/pgm-ScanTrackingIds.txt b/Documentation/pgm-ScanTrackingIds.txt
index f9494d4..9e38032 100644
--- a/Documentation/pgm-ScanTrackingIds.txt
+++ b/Documentation/pgm-ScanTrackingIds.txt
@@ -57,3 +57,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/pgm-daemon.txt b/Documentation/pgm-daemon.txt
index 4b920ea..18bd293 100644
--- a/Documentation/pgm-daemon.txt
+++ b/Documentation/pgm-daemon.txt
@@ -126,3 +126,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/pgm-gsql.txt b/Documentation/pgm-gsql.txt
index 37fbb74..a805036 100644
--- a/Documentation/pgm-gsql.txt
+++ b/Documentation/pgm-gsql.txt
@@ -54,3 +54,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/pgm-index.txt b/Documentation/pgm-index.txt
index 987b4ac..a25a1ab 100644
--- a/Documentation/pgm-index.txt
+++ b/Documentation/pgm-index.txt
@@ -44,3 +44,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/pgm-init.txt b/Documentation/pgm-init.txt
index 3d6cb73..8e48b30 100644
--- a/Documentation/pgm-init.txt
+++ b/Documentation/pgm-init.txt
@@ -62,3 +62,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/pgm-prolog-shell.txt b/Documentation/pgm-prolog-shell.txt
index 3189e90..7b273f5 100644
--- a/Documentation/pgm-prolog-shell.txt
+++ b/Documentation/pgm-prolog-shell.txt
@@ -55,3 +55,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/pgm-reindex.txt b/Documentation/pgm-reindex.txt
index 2b44f6b..f55c093 100644
--- a/Documentation/pgm-reindex.txt
+++ b/Documentation/pgm-reindex.txt
@@ -39,3 +39,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/pgm-rulec.txt b/Documentation/pgm-rulec.txt
index 6d0a632..356f555 100644
--- a/Documentation/pgm-rulec.txt
+++ b/Documentation/pgm-rulec.txt
@@ -52,3 +52,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/project-setup.txt b/Documentation/project-setup.txt
index 36d3c60..9b6f6d9 100644
--- a/Documentation/project-setup.txt
+++ b/Documentation/project-setup.txt
@@ -134,3 +134,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/prolog-change-facts.txt b/Documentation/prolog-change-facts.txt
index e21da02..071984b 100644
--- a/Documentation/prolog-change-facts.txt
+++ b/Documentation/prolog-change-facts.txt
@@ -101,3 +101,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/prolog-cookbook.txt b/Documentation/prolog-cookbook.txt
index b1710a2..54f6910 100644
--- a/Documentation/prolog-cookbook.txt
+++ b/Documentation/prolog-cookbook.txt
@@ -1062,3 +1062,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/replace_macros.py b/Documentation/replace_macros.py
index 1680a47..1f23cbe 100755
--- a/Documentation/replace_macros.py
+++ b/Documentation/replace_macros.py
@@ -22,6 +22,7 @@
 PAT_GET = re.compile(r'^get::([^ \t\n]*)')
 PAT_TITLE = re.compile(r'^\.(.*)')
 PAT_STARS = re.compile(r'^\*\*\*\*')
+PAT_SEARCHBOX = re.compile(r'^SEARCHBOX')
 
 GERRIT_UPLINK = """
 
@@ -56,6 +57,29 @@
 
 """
 
+SEARCH_BOX = """
+
+++++
+<div style="position:absolute; right:20px; top:20px;">
+<input type="text" id="docSearch" size="70" />
+<button type="button" id="searchBox">Search</button>
+<script type="text/javascript">
+var f = function() {
+  window.location = '../#/Documentation/' +
+    encodeURIComponent(document.getElementById("docSearch").value);
+}
+document.getElementById("searchBox").onclick = f;
+document.getElementById("docSearch").onkeypress = function(e) {
+  if (13 == (e.keyCode ? e.keyCode : e.which)) {
+    f();
+  }
+}
+</script>
+</div>
+++++
+
+"""
+
 opts = OptionParser()
 opts.add_option('-o', '--out', help='output file')
 opts.add_option('-s', '--src', help='source file')
@@ -73,6 +97,10 @@
       # Case of "GERRIT\n------" at the footer
       out_file.write(GERRIT_UPLINK)
       last_line = ''
+    elif PAT_SEARCHBOX.match(line):
+      # Case of 'SEARCHBOX\n---------'
+      out_file.write(SEARCH_BOX)
+      last_line = ''
     elif PAT_INCLUDE.match(line):
       # Case of 'include::<filename>'
       match = PAT_INCLUDE.match(line)
diff --git a/Documentation/rest-api-access.txt b/Documentation/rest-api-access.txt
index 6c786e4..b49f787 100644
--- a/Documentation/rest-api-access.txt
+++ b/Documentation/rest-api-access.txt
@@ -378,3 +378,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/rest-api-accounts.txt b/Documentation/rest-api-accounts.txt
index 02bb549..52c6ac9 100644
--- a/Documentation/rest-api-accounts.txt
+++ b/Documentation/rest-api-accounts.txt
@@ -200,14 +200,17 @@
   GET /accounts/john.doe@example.com/active HTTP/1.0
 ----
 
-As response `200 OK` is returned for an active account and
-`404 Not Found` is returned for an inactive account.
+If the account is active the string `ok` is returned.
 
 .Response
 ----
   HTTP/1.1 200 OK
+
+  ok
 ----
 
+If the account is inactive the response is `204 No Content`.
+
 [[set-active]]
 Set Active
 ~~~~~~~~~~
@@ -921,6 +924,84 @@
   }
 ----
 
+Get Starred Changes
+~~~~~~~~~~~~~~~~~~~
+[verse]
+'GET /accounts/link:#account-id[\{account-id\}]/starred.changes'
+
+Gets the changes starred by the identified user account. This
+URL endpoint is functionally identical to the changes query
+`GET /changes/?q=is:starred`. The result is a list of
+link:rest-api-changes.html#change-info[ChangeInfo] entities.
+
+.Request
+----
+  GET /a/accounts/self/starred.changes
+----
+
+.Response
+----
+  HTTP/1.1 200 OK
+  Content-Disposition: attachment
+  Content-Type: application/json;charset=UTF-8
+
+  )]}'
+  [
+    {
+      "kind": "gerritcodereview#change",
+      "id": "myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940",
+      "project": "myProject",
+      "branch": "master",
+      "change_id": "I8473b95934b5732ac55d26311a706c9c2bde9940",
+      "subject": "Implementing Feature X",
+      "status": "NEW",
+      "created": "2013-02-01 09:59:32.126000000",
+      "updated": "2013-02-21 11:16:36.775000000",
+      "mergeable": true,
+      "_sortkey": "0023412400000f7d",
+      "_number": 3965,
+      "owner": {
+        "name": "John Doe"
+      }
+    }
+  ]
+----
+
+Star Change
+~~~~~~~~~~~
+[verse]
+'PUT /accounts/link:#account-id[\{account-id\}]/starred.changes/link:rest-api-changes.html#change-id[\{change-id\}]'
+
+Star a change. Starred changes are returned for the search query
+`is:starred` or `starredby:USER` and automatically notify the user
+whenever updates are made to the change.
+
+.Request
+----
+  PUT /a/accounts/self/starred.changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940 HTTP/1.0
+----
+
+.Response
+----
+  HTTP/1.1 204 No Content
+----
+
+Unstar Change
+~~~~~~~~~~~~~
+[verse]
+'DELETE /accounts/link:#account-id[\{account-id\}]/starred.changes/link:rest-api-changes#change-id[\{change-id\}]'
+
+Unstar a change. Removes the starred flag, stopping notifications.
+
+.Request
+----
+  DELETE /a/accounts/self/starred.changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940 HTTP/1.0
+----
+
+.Response
+----
+  HTTP/1.1 204 No Content
+----
 
 [[ids]]
 IDs
@@ -1250,3 +1331,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index 9404d00..9ed8be0 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -3371,3 +3371,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/rest-api-config.txt b/Documentation/rest-api-config.txt
index 4f25aa8..9a512b8 100644
--- a/Documentation/rest-api-config.txt
+++ b/Documentation/rest-api-config.txt
@@ -181,7 +181,7 @@
 ~~~~~~~~~~~~~~
 The `CapabilityInfo` entity contains information about a capability.
 
-[options="header",width="50%",cols="1,5"]
+[options="header",width="50%",cols="1,6"]
 |=================================
 |Field Name           |Description
 |`kind`               |`gerritcodereview#capability`
@@ -195,7 +195,7 @@
 The `TopMenuEntryInfo` entity contains information about a top menu
 entry.
 
-[options="header",width="50%",cols="1,5"]
+[options="header",width="50%",cols="1,6"]
 |=================================
 |Field Name           |Description
 |`name`               |Name of the top menu entry.
@@ -208,14 +208,18 @@
 The `TopMenuItemInfo` entity contains information about a menu item in
 a top menu entry.
 
-[options="header",width="50%",cols="1,5"]
-|=================================
-|Field Name           |Description
-|`url`                |The URL of the menu item link.
-|`name`               |The name of the menu item.
-|`target`             |Target attribute of the menu item link.
-|=================================
+[options="header",width="50%",cols="1,^1,5"]
+|========================
+|Field Name ||Description
+|`url`      ||The URL of the menu item link.
+|`name`     ||The name of the menu item.
+|`target`   ||Target attribute of the menu item link.
+|`id`       |optional|The `id` attribute of the menu item link.
+|========================
 
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/rest-api-documentation.txt b/Documentation/rest-api-documentation.txt
index db7dc35..9030fac 100644
--- a/Documentation/rest-api-documentation.txt
+++ b/Documentation/rest-api-documentation.txt
@@ -149,3 +149,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/rest-api-groups.txt b/Documentation/rest-api-groups.txt
index 6289e5a..e96607c 100644
--- a/Documentation/rest-api-groups.txt
+++ b/Documentation/rest-api-groups.txt
@@ -1239,3 +1239,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/rest-api-plugins.txt b/Documentation/rest-api-plugins.txt
index 0c69f7d..f5b6809 100644
--- a/Documentation/rest-api-plugins.txt
+++ b/Documentation/rest-api-plugins.txt
@@ -277,3 +277,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/rest-api-projects.txt b/Documentation/rest-api-projects.txt
index 35db183..1ac232a 100644
--- a/Documentation/rest-api-projects.txt
+++ b/Documentation/rest-api-projects.txt
@@ -1515,3 +1515,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/rest-api.txt b/Documentation/rest-api.txt
index 788f222..bedf218 100644
--- a/Documentation/rest-api.txt
+++ b/Documentation/rest-api.txt
@@ -171,3 +171,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/user-changeid.txt b/Documentation/user-changeid.txt
index c13faa6..ca60819 100644
--- a/Documentation/user-changeid.txt
+++ b/Documentation/user-changeid.txt
@@ -169,3 +169,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/user-dashboards.txt b/Documentation/user-dashboards.txt
index 0945153..1c5162a 100644
--- a/Documentation/user-dashboards.txt
+++ b/Documentation/user-dashboards.txt
@@ -169,3 +169,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/user-notify.txt b/Documentation/user-notify.txt
index 558dcb5..dd7d4bd 100644
--- a/Documentation/user-notify.txt
+++ b/Documentation/user-notify.txt
@@ -145,3 +145,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/user-search.txt b/Documentation/user-search.txt
index 37040ea..cb3a3b6 100644
--- a/Documentation/user-search.txt
+++ b/Documentation/user-search.txt
@@ -74,6 +74,14 @@
 Either a legacy numerical 'ID' such as 15183, or a newer style
 Change-Id that was scraped out of the commit message.
 
+[[conflicts]]
+conflicts:'ID'::
++
+Changes that potentially conflict with change 'ID' because they touch
+at least one file that was also touched by change 'ID'. Change 'ID' can
+be specified as a legacy numerical 'ID' such as 15183, or a newer style
+Change-Id that was scraped out of the commit message.
+
 [[owner]]
 owner:'USER'::
 +
@@ -460,3 +468,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/user-signedoffby.txt b/Documentation/user-signedoffby.txt
index 56858bf..c5ae135 100644
--- a/Documentation/user-signedoffby.txt
+++ b/Documentation/user-signedoffby.txt
@@ -175,3 +175,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/user-submodules.txt b/Documentation/user-submodules.txt
index 6aab43f..fbf45d7 100644
--- a/Documentation/user-submodules.txt
+++ b/Documentation/user-submodules.txt
@@ -187,3 +187,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/user-upload.txt b/Documentation/user-upload.txt
index cbb152c3..17c4acf 100644
--- a/Documentation/user-upload.txt
+++ b/Documentation/user-upload.txt
@@ -366,6 +366,15 @@
   git push ssh://john.doe@git.example.com:29418/kernel/common HEAD:refs/for/master%base=$(git rev-parse origin/master)
 ====
 
+It is also possible to specify more than one '%base' argument.
+This may be useful when pushing a merge commit. Note that the '%'
+character has only to be provided once, for the first '%base'
+argument:
+
+====
+  git push ssh://john.doe@git.example.com:29418/kernel/common HEAD:refs/for/master%base=commit-id1,base=commit-id2
+====
+
 
 repo upload
 -----------
@@ -445,3 +454,6 @@
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/ReleaseNotes/ReleaseNotes-2.8.txt b/ReleaseNotes/ReleaseNotes-2.8.txt
index 94299e1..27ed297 100644
--- a/ReleaseNotes/ReleaseNotes-2.8.txt
+++ b/ReleaseNotes/ReleaseNotes-2.8.txt
@@ -735,7 +735,7 @@
 Upgrades
 --------
 
-* Update JGit to 3.0.0.201306101825-r.41-g84d2738
+* Update JGit to 3.1.0.201310021548-r
 * Update gwtorm to 1.7
 * Update guice to 4.0-beta
 * Update guava to 15.0
diff --git a/ReleaseNotes/ReleaseNotes-2.9.txt b/ReleaseNotes/ReleaseNotes-2.9.txt
new file mode 100644
index 0000000..e4aa124
--- /dev/null
+++ b/ReleaseNotes/ReleaseNotes-2.9.txt
@@ -0,0 +1,79 @@
+Release notes for Gerrit 2.9
+============================
+
+
+Gerrit 2.9 is now available:
+
+link:https://gerrit-releases.storage.googleapis.com/gerrit-2.9.war[
+https://gerrit-releases.storage.googleapis.com/gerrit-2.9.war]
+
+
+Schema Change
+-------------
+
+
+*WARNING:* This release contains schema changes.  To upgrade:
+----
+  java -jar gerrit.war init -d site_path
+----
+
+*WARNING:* Upgrading to 2.9.x requires the server be first upgraded to 2.1.7 (or
+a later 2.1.x version), and then to 2.9.x.  If you are upgrading from 2.2.x.x or
+later, you may ignore this warning and upgrade directly to 2.9.x.
+
+
+Release Highlights
+------------------
+
+
+* 'Gerrit Inspector' for interactive inspection and troubleshooting of a running
+Gerrit instance.
+
+
+New Features
+------------
+
+
+ssh
+~~~
+
+
+* New `--all-reviewers` option on the `query` command allowing query results
+to include information about all reviewers added on the change.
+
+* New link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/cmd-apropos.html[
+`apropos` command] to search the Gerrit documentation.
+
+
+REST API
+~~~~~~~~
+
+
+Documentation
+^^^^^^^^^^^^^
+
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/rest-api-documentation#search-documentation.html[
+Search documentation].
+
+Daemon
+~~~~~~
+
+
+* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/dev-inspector.html[
+Gerrit Inspector]: interactive Jython shell.
++
+New `-s` option is added to the Daemon to start an interactive Jython shell for inspection and
+troubleshooting of live data of the Gerrit instance.
+
+
+Bug Fixes
+---------
+
+
+Configuration
+~~~~~~~~~~~~~
+
+
+* The number of accounts shown on the 'Become Any Account' login
+screen is increased from 5 to 100.
diff --git a/ReleaseNotes/index.txt b/ReleaseNotes/index.txt
index 28b9f65..effb0d4 100644
--- a/ReleaseNotes/index.txt
+++ b/ReleaseNotes/index.txt
@@ -1,6 +1,11 @@
 Gerrit Code Review - Release Notes
 ==================================
 
+[[2_9]]
+Version 2.9.x
+-------------
+* link:ReleaseNotes-2.9.html[2.9]
+
 [[2_8]]
 Version 2.8.x
 -------------
diff --git a/contrib/themes/spotify/static/background-gradient.png b/contrib/themes/spotify/static/background-gradient.png
index b40f35b..3b9422e 100644
--- a/contrib/themes/spotify/static/background-gradient.png
+++ b/contrib/themes/spotify/static/background-gradient.png
Binary files differ
diff --git a/contrib/themes/spotify/static/logo.png b/contrib/themes/spotify/static/logo.png
index bfe1fce..c231031 100644
--- a/contrib/themes/spotify/static/logo.png
+++ b/contrib/themes/spotify/static/logo.png
Binary files differ
diff --git a/gerrit-acceptance-tests/BUCK b/gerrit-acceptance-tests/BUCK
index 11311e8..cb946d6 100644
--- a/gerrit-acceptance-tests/BUCK
+++ b/gerrit-acceptance-tests/BUCK
@@ -7,7 +7,9 @@
     '//gerrit-common:server',
     '//gerrit-extension-api:api',
     '//gerrit-launcher:launcher',
+    '//gerrit-lucene:lucene',
     '//gerrit-httpd:httpd',
+    '//gerrit-pgm:init-base',
     '//gerrit-pgm:pgm',
     '//gerrit-reviewdb:server',
     '//gerrit-server:server',
@@ -30,6 +32,7 @@
     '//lib/guice:guice',
     '//lib/jgit:jgit',
     '//lib/jgit:junit',
+    '//lib/mina:sshd',
   ],
   export_deps = True,
   visibility = [
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
index 784b461..b24ec47 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
@@ -55,10 +55,14 @@
   }
 
   private void beforeTest(Config cfg, boolean memory) throws Exception {
-    server = GerritServer.start(cfg, memory);
+    server = startServer(cfg, memory);
     server.getTestInjector().injectMembers(this);
   }
 
+  protected GerritServer startServer(Config cfg, boolean memory) throws Exception {
+    return GerritServer.start(cfg, memory);
+  }
+
   private void afterTest() throws Exception {
     server.stop();
   }
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTestWithSecondaryIndex.java
similarity index 64%
copy from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
copy to gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTestWithSecondaryIndex.java
index a5371d2..7ab5911 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTestWithSecondaryIndex.java
@@ -12,19 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.acceptance.rest.change;
+package com.google.gerrit.acceptance;
 
-import com.google.common.collect.Maps;
+import org.eclipse.jgit.lib.Config;
 
-import java.util.Map;
+public class AbstractDaemonTestWithSecondaryIndex extends AbstractDaemonTest {
 
-public class ReviewInput {
-  Map<String, Integer> labels;
-
-  public static ReviewInput approve() {
-    ReviewInput in = new ReviewInput();
-    in.labels = Maps.newHashMap();
-    in.labels.put("Code-Review", 2);
-    return in;
+  @Override
+  protected GerritServer startServer(Config cfg, boolean memory)
+      throws Exception {
+    return GerritServer.start(cfg, memory, true);
   }
 }
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
new file mode 100644
index 0000000..63bdfd2
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AcceptanceTestRequestScope.java
@@ -0,0 +1,186 @@
+// 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.acceptance;
+
+import com.google.common.collect.Maps;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.RequestCleanup;
+import com.google.gerrit.server.config.RequestScopedReviewDbProvider;
+import com.google.gerrit.server.util.RequestContext;
+import com.google.gerrit.server.util.ThreadLocalRequestContext;
+import com.google.gerrit.server.util.ThreadLocalRequestScopePropagator;
+import com.google.gerrit.server.util.TimeUtil;
+import com.google.gwtorm.server.SchemaFactory;
+import com.google.inject.Inject;
+import com.google.inject.Key;
+import com.google.inject.OutOfScopeException;
+import com.google.inject.Provider;
+import com.google.inject.Scope;
+import com.google.inject.util.Providers;
+
+import java.util.Map;
+
+/** Guice scopes for state during an Acceptance Test connection. */
+public class AcceptanceTestRequestScope {
+  private static final Key<RequestCleanup> RC_KEY =
+      Key.get(RequestCleanup.class);
+
+  private static final Key<RequestScopedReviewDbProvider> DB_KEY =
+      Key.get(RequestScopedReviewDbProvider.class);
+
+  public class Context implements RequestContext {
+    private final RequestCleanup cleanup = new RequestCleanup();
+    private final Map<Key<?>, Object> map = Maps.newHashMap();
+    private final SchemaFactory<ReviewDb> schemaFactory;
+    private final SshSession session;
+    private final CurrentUser user;
+
+    final long created;
+    volatile long started;
+    volatile long finished;
+
+    private Context(SchemaFactory<ReviewDb> sf, SshSession s,
+        CurrentUser u, long at) {
+      schemaFactory = sf;
+      session = s;
+      user = u;
+      created = started = finished = at;
+      map.put(RC_KEY, cleanup);
+      map.put(DB_KEY, new RequestScopedReviewDbProvider(
+          schemaFactory,
+          Providers.of(cleanup)));
+    }
+
+    private Context(Context p, SshSession s, CurrentUser c) {
+      this(p.schemaFactory, s, c, p.created);
+      started = p.started;
+      finished = p.finished;
+    }
+
+    SshSession getSession() {
+      return session;
+    }
+
+    @Override
+    public CurrentUser getCurrentUser() {
+      if (user == null) {
+        throw new IllegalStateException("user == null, forgot to set it?");
+      }
+      return user;
+    }
+
+    @Override
+    public Provider<ReviewDb> getReviewDbProvider() {
+      return (RequestScopedReviewDbProvider) map.get(DB_KEY);
+    }
+
+    synchronized <T> T get(Key<T> key, Provider<T> creator) {
+      @SuppressWarnings("unchecked")
+      T t = (T) map.get(key);
+      if (t == null) {
+        t = creator.get();
+        map.put(key, t);
+      }
+      return t;
+    }
+  }
+
+  static class ContextProvider implements Provider<Context> {
+    @Override
+    public Context get() {
+      return requireContext();
+    }
+  }
+
+  static class SshSessionProvider implements Provider<SshSession> {
+    @Override
+    public SshSession get() {
+      return requireContext().getSession();
+    }
+  }
+
+  static class Propagator extends ThreadLocalRequestScopePropagator<Context> {
+    private final AcceptanceTestRequestScope atrScope;
+
+    @Inject
+    Propagator(AcceptanceTestRequestScope atrScope, ThreadLocalRequestContext local,
+        Provider<RequestScopedReviewDbProvider> dbProviderProvider) {
+      super(REQUEST, current, local, dbProviderProvider);
+      this.atrScope = atrScope;
+    }
+
+    @Override
+    protected Context continuingContext(Context ctx) {
+      // The cleanup is not chained, since the RequestScopePropagator executors
+      // the Context's cleanup when finished executing.
+      return atrScope.newContinuingContext(ctx);
+    }
+  }
+
+  private static final ThreadLocal<Context> current =
+      new ThreadLocal<Context>();
+
+  private static Context requireContext() {
+    final Context ctx = current.get();
+    if (ctx == null) {
+      throw new OutOfScopeException("Not in command/request");
+    }
+    return ctx;
+  }
+
+  private final ThreadLocalRequestContext local;
+
+  @Inject
+  AcceptanceTestRequestScope(ThreadLocalRequestContext local) {
+    this.local = local;
+  }
+
+  public Context newContext(SchemaFactory<ReviewDb> sf, SshSession s, CurrentUser user) {
+    return new Context(sf, s, user, TimeUtil.nowMs());
+  }
+
+  private Context newContinuingContext(Context ctx) {
+    return new Context(ctx, ctx.getSession(), ctx.getCurrentUser());
+  }
+
+  public Context set(Context ctx) {
+    Context old = current.get();
+    current.set(ctx);
+    local.setContext(ctx);
+    return old;
+  }
+
+  /** Returns exactly one instance per command executed. */
+  static final Scope REQUEST = new Scope() {
+    public <T> Provider<T> scope(final Key<T> key, final Provider<T> creator) {
+      return new Provider<T>() {
+        public T get() {
+          return requireContext().get(key, creator);
+        }
+
+        @Override
+        public String toString() {
+          return String.format("%s[%s]", creator, REQUEST);
+        }
+      };
+    }
+
+    @Override
+    public String toString() {
+      return "Acceptance Test Scope.REQUEST";
+    }
+  };
+}
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 daf9d38..30eb93c 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
@@ -15,10 +15,13 @@
 package com.google.gerrit.acceptance;
 
 import com.google.common.collect.ImmutableList;
+import com.google.gerrit.lucene.LuceneIndexModule;
 import com.google.gerrit.pgm.Daemon;
 import com.google.gerrit.pgm.Init;
+import com.google.gerrit.pgm.Reindex;
 import com.google.gerrit.server.config.FactoryModule;
 import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.index.ChangeSchemas;
 import com.google.gerrit.server.util.SocketUtil;
 import com.google.inject.Injector;
 import com.google.inject.Key;
@@ -48,6 +51,12 @@
 
   /** Returns fully started Gerrit server */
   static GerritServer start(Config base, boolean memory) throws Exception {
+    return start(base, memory, false);
+  }
+
+  /** Returns fully started Gerrit server */
+  static GerritServer start(Config base, boolean memory, boolean index)
+      throws Exception {
     final CyclicBarrier serverStarted = new CyclicBarrier(2);
     final Daemon daemon = new Daemon(new Runnable() {
       public void run() {
@@ -69,11 +78,25 @@
       mergeTestConfig(cfg);
       cfg.setBoolean("httpd", null, "requestLog", false);
       cfg.setBoolean("sshd", null, "requestLog", false);
+      if (index) {
+        cfg.setString("index", null, "type", "lucene");
+        cfg.setBoolean("index", "lucene", "testInmemory", true);
+        daemon.setLuceneModule(new LuceneIndexModule(
+            ChangeSchemas.getLatest().getVersion(),
+            Runtime.getRuntime().availableProcessors(), null));
+      }
       daemon.setDatabaseForTesting(ImmutableList.<Module>of(
           new InMemoryTestingDatabaseModule(cfg)));
       daemon.start();
     } else {
-      site = initSite(base);
+      Config cfg = base != null ? base : new Config();
+      if (index) {
+        cfg.setString("index", null, "type", "lucene");
+      }
+      site = initSite(cfg);
+      if (index) {
+        reindex(site);
+      }
       daemonService = Executors.newSingleThreadExecutor();
       daemonService.submit(new Callable<Void>() {
         public Void call() throws Exception {
@@ -84,7 +107,7 @@
             serverStarted.reset();
           }
           return null;
-        };
+        }
       });
       serverStarted.await();
       System.out.println("Gerrit Server Started");
@@ -114,6 +137,15 @@
     return tmp;
   }
 
+  /** Runs the reindex command. Works only if the site is not currently running. */
+  private static void reindex(File site) throws Exception {
+    Reindex reindex = new Reindex();
+    int rc = reindex.main(new String[] {"-d", site.getPath()});
+    if (rc != 0) {
+      throw new RuntimeException("Reindex failed");
+    }
+  }
+
   private static void mergeTestConfig(Config cfg)
       throws IOException {
     InetSocketAddress http = newPort();
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java
index 5576c4f..8548b5c 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java
@@ -34,7 +34,6 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.gwtorm.server.OrmRuntimeException;
 import com.google.gwtorm.server.SchemaFactory;
-import com.google.inject.AbstractModule;
 import com.google.inject.Inject;
 import com.google.inject.Provides;
 import com.google.inject.Singleton;
@@ -46,7 +45,7 @@
 
 import java.io.File;
 
-class InMemoryTestingDatabaseModule extends AbstractModule {
+class InMemoryTestingDatabaseModule extends LifecycleModule {
   private final Config cfg;
 
   InMemoryTestingDatabaseModule(Config cfg) {
@@ -71,12 +70,7 @@
     bind(new TypeLiteral<SchemaFactory<ReviewDb>>() {})
       .to(InMemoryDatabase.class);
 
-    install(new LifecycleModule() {
-      @Override
-      protected void configure() {
-        listener().to(CreateDatabase.class);
-      }
-    });
+    listener().to(CreateDatabase.class);
 
     bind(SitePaths.class);
     bind(TrackingFooters.class)
@@ -126,4 +120,4 @@
       mem.drop();
     }
   }
-}
\ No newline at end of file
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/TestAccount.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/TestAccount.java
index b85ffea..31ed136 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/TestAccount.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/TestAccount.java
@@ -58,4 +58,8 @@
         server.getHttpAddress().getAddress().getHostAddress(),
         server.getHttpAddress().getPort());
   }
+
+  public Account.Id getId() {
+    return id;
+  }
 }
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/UseGerritConfigAnnotationTest.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/UseGerritConfigAnnotationTest.java
index 0931e12..88d46a4 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/UseGerritConfigAnnotationTest.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/UseGerritConfigAnnotationTest.java
@@ -37,7 +37,7 @@
   @Test
   @GerritConfigs({
       @GerritConfig(name="x.y", value="z"),
-      @GerritConfig(name="a.b", value="c"),
+      @GerritConfig(name="a.b", value="c")
   })
   public void testMultiple() {
     assertEquals("z", serverConfig.getString("x", null, "y"));
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
new file mode 100644
index 0000000..94e6f6a
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/BUCK
@@ -0,0 +1,6 @@
+include_defs('//gerrit-acceptance-tests/tests.defs')
+
+acceptance_tests(
+  srcs = glob(['*IT.java']),
+  deps = ['//gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git:util'],
+)
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
new file mode 100644
index 0000000..dc65470
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -0,0 +1,145 @@
+// 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.acceptance.api.change;
+
+import static com.google.gerrit.acceptance.git.GitUtil.cloneProject;
+import static com.google.gerrit.acceptance.git.GitUtil.createProject;
+import static com.google.gerrit.acceptance.git.GitUtil.initSsh;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.AcceptanceTestRequestScope;
+import com.google.gerrit.acceptance.AccountCreator;
+import com.google.gerrit.acceptance.SshSession;
+import com.google.gerrit.acceptance.TestAccount;
+import com.google.gerrit.acceptance.git.PushOneCommit;
+import com.google.gerrit.extensions.api.GerritApi;
+import com.google.gerrit.extensions.api.changes.ReviewInput;
+import com.google.gerrit.extensions.restapi.ResourceConflictException;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.gwtorm.server.SchemaFactory;
+import com.google.inject.Inject;
+import com.google.inject.util.Providers;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+
+public class ChangeIT extends AbstractDaemonTest {
+
+  @Inject
+  private AccountCreator accounts;
+
+  @Inject
+  private SchemaFactory<ReviewDb> reviewDbProvider;
+
+  @Inject
+  private GerritApi gApi;
+
+  @Inject
+  private AcceptanceTestRequestScope atrScope;
+
+  @Inject
+  private IdentifiedUser.GenericFactory identifiedUserFactory;
+
+  private TestAccount admin;
+  private Git git;
+  private ReviewDb db;
+
+  @Before
+  public void setUp() throws Exception {
+    admin = accounts.admin();
+    initSsh(admin);
+    Project.NameKey project = new Project.NameKey("p");
+    SshSession sshSession = new SshSession(server, admin);
+    createProject(sshSession, project.get());
+    git = cloneProject(sshSession.getUrl() + "/" + project.get());
+    db = reviewDbProvider.open();
+    atrScope.set(atrScope.newContext(reviewDbProvider, sshSession,
+        identifiedUserFactory.create(Providers.of(db), admin.getId())));
+  }
+
+  @After
+  public void cleanup() {
+    db.close();
+  }
+
+  @Test
+  public void abandon() throws GitAPIException,
+      IOException, RestApiException {
+    PushOneCommit.Result r = createChange();
+    gApi.changes()
+        .id("p~master~" + r.getChangeId())
+        .abandon();
+  }
+
+  @Test
+  public void restore() throws GitAPIException,
+      IOException, RestApiException {
+    PushOneCommit.Result r = createChange();
+    gApi.changes()
+        .id("p~master~" + r.getChangeId())
+        .abandon();
+    gApi.changes()
+        .id("p~master~" + r.getChangeId())
+        .restore();
+  }
+
+  @Test
+  public void revert() throws GitAPIException,
+      IOException, RestApiException {
+    PushOneCommit.Result r = createChange();
+    gApi.changes()
+        .id("p~master~" + r.getChangeId())
+        .revision(r.getCommit().name())
+        .review(approve());
+    gApi.changes()
+        .id("p~master~" + r.getChangeId())
+        .revision(r.getCommit().name())
+        .submit();
+    gApi.changes()
+        .id("p~master~" + r.getChangeId())
+        .revert();
+  }
+
+  // Change is already up to date
+  @Test(expected = ResourceConflictException.class)
+  public void rebase() throws GitAPIException,
+      IOException, RestApiException {
+    PushOneCommit.Result r = createChange();
+    gApi.changes()
+        .id("p~master~" + r.getChangeId())
+        .revision(r.getCommit().name())
+        .rebase();
+  }
+
+  private PushOneCommit.Result createChange() throws GitAPIException,
+      IOException {
+    PushOneCommit push = new PushOneCommit(db, admin.getIdent());
+    return push.to(git, "refs/for/master");
+  }
+
+  private static ReviewInput approve() {
+    return new ReviewInput()
+      .message("Looks good!")
+      .label("Code-Review", 2);
+  }
+}
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
new file mode 100644
index 0000000..94e6f6a
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/BUCK
@@ -0,0 +1,6 @@
+include_defs('//gerrit-acceptance-tests/tests.defs')
+
+acceptance_tests(
+  srcs = glob(['*IT.java']),
+  deps = ['//gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git:util'],
+)
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java
new file mode 100644
index 0000000..d60a904
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java
@@ -0,0 +1,143 @@
+// 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.acceptance.api.revision;
+
+import static com.google.gerrit.acceptance.git.GitUtil.cloneProject;
+import static com.google.gerrit.acceptance.git.GitUtil.createProject;
+import static com.google.gerrit.acceptance.git.GitUtil.initSsh;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.AcceptanceTestRequestScope;
+import com.google.gerrit.acceptance.AccountCreator;
+import com.google.gerrit.acceptance.SshSession;
+import com.google.gerrit.acceptance.TestAccount;
+import com.google.gerrit.acceptance.git.PushOneCommit;
+import com.google.gerrit.extensions.api.GerritApi;
+import com.google.gerrit.extensions.api.changes.ReviewInput;
+import com.google.gerrit.extensions.api.changes.RevisionApi;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.gwtorm.server.SchemaFactory;
+import com.google.inject.Inject;
+import com.google.inject.util.Providers;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+
+public class RevisionIT extends AbstractDaemonTest {
+
+  @Inject
+  private AccountCreator accounts;
+
+  @Inject
+  private SchemaFactory<ReviewDb> reviewDbProvider;
+
+  @Inject
+  private GerritApi gApi;
+
+  @Inject
+  private AcceptanceTestRequestScope atrScope;
+
+  @Inject
+  private IdentifiedUser.GenericFactory identifiedUserFactory;
+
+  private TestAccount admin;
+  private Git git;
+  private ReviewDb db;
+
+  @Before
+  public void setUp() throws Exception {
+    admin = accounts.admin();
+    initSsh(admin);
+    Project.NameKey project = new Project.NameKey("p");
+    SshSession sshSession = new SshSession(server, admin);
+    createProject(sshSession, project.get());
+    git = cloneProject(sshSession.getUrl() + "/" + project.get());
+    db = reviewDbProvider.open();
+    atrScope.set(atrScope.newContext(reviewDbProvider, sshSession,
+        identifiedUserFactory.create(Providers.of(db), admin.getId())));
+  }
+
+  @After
+  public void cleanup() {
+    db.close();
+  }
+
+  @Test
+  public void reviewTriplet() throws GitAPIException,
+      IOException, RestApiException {
+    PushOneCommit.Result r = createChange();
+    gApi.changes()
+        .id("p~master~" + r.getChangeId())
+        .revision(r.getCommit().name())
+        .review(approve());
+  }
+
+  @Test
+  public void reviewId() throws GitAPIException,
+      IOException, RestApiException {
+    PushOneCommit.Result r = createChange();
+    gApi.changes()
+        .id(r.getChangeId())
+        .current()
+        .review(approve());
+  }
+
+  @Test
+  public void submit() throws GitAPIException,
+      IOException, RestApiException {
+    PushOneCommit.Result r = createChange();
+    RevisionApi rApi = gApi.changes()
+        .id("p~master~" + r.getChangeId())
+        .current();
+    rApi.review(approve());
+    rApi.submit();
+  }
+
+  @Test
+  public void deleteDraft() throws GitAPIException,
+      IOException, RestApiException {
+    PushOneCommit.Result r = createDraft();
+    gApi.changes()
+        .id(r.getChangeId())
+        .revision(r.getCommit().name())
+        .delete();
+  }
+
+  private PushOneCommit.Result createChange() throws GitAPIException,
+      IOException {
+    PushOneCommit push = new PushOneCommit(db, admin.getIdent());
+    return push.to(git, "refs/for/master");
+  }
+
+  private PushOneCommit.Result createDraft() throws GitAPIException,
+      IOException {
+    PushOneCommit push = new PushOneCommit(db, admin.getIdent());
+    return push.to(git, "refs/drafts/master");
+  }
+
+  private static ReviewInput approve() {
+    return new ReviewInput()
+      .message("Looks good!")
+      .label("Code-Review", 2);
+  }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/GitUtil.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/GitUtil.java
index c17598f..3d1b009 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/GitUtil.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/GitUtil.java
@@ -28,6 +28,7 @@
 import org.eclipse.jgit.api.CheckoutCommand;
 import org.eclipse.jgit.api.CloneCommand;
 import org.eclipse.jgit.api.CommitCommand;
+import org.eclipse.jgit.api.FetchCommand;
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.PushCommand;
 import org.eclipse.jgit.api.errors.GitAPIException;
@@ -105,10 +106,15 @@
   }
 
   public static Git cloneProject(String url) throws GitAPIException, IOException {
+    return cloneProject(url, true);
+  }
+
+  public static Git cloneProject(String url, boolean checkout) throws GitAPIException, IOException {
     final File gitDir = TempFileUtil.createTempDirectory();
     final CloneCommand cloneCmd = Git.cloneRepository();
     cloneCmd.setURI(url);
     cloneCmd.setDirectory(gitDir);
+    cloneCmd.setNoCheckout(!checkout);
     return cloneCmd.call();
   }
 
@@ -178,6 +184,12 @@
     }
   }
 
+  public static void fetch(Git git, String spec) throws GitAPIException {
+    FetchCommand fetch = git.fetch();
+    fetch.setRefSpecs(new RefSpec(spec));
+    fetch.call();
+  }
+
   public static void checkout(Git git, String name) throws GitAPIException {
     CheckoutCommand checkout = git.checkout();
     checkout.setName(name);
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 d813501..8b7d091 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,12 +2,20 @@
 
 acceptance_tests(
   srcs = glob(['*IT.java']),
-  deps = [':util'],
+  deps = [
+    ':util',
+    '//gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git:util',
+    '//gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change:util',
+  ],
 )
 
 java_library(
   name = 'util',
-  srcs = ['AccountAssert.java', 'AccountInfo.java'],
+  srcs = [
+    'AccountAssert.java',
+    'AccountInfo.java',
+    'CapabilityInfo.java',
+  ],
   deps = [
     '//gerrit-acceptance-tests:lib',
     '//gerrit-reviewdb:server',
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/CapabilitiesIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/CapabilitiesIT.java
new file mode 100644
index 0000000..e22220a
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/CapabilitiesIT.java
@@ -0,0 +1,150 @@
+// 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.acceptance.rest.account;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.AccountCreator;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.acceptance.RestSession;
+import com.google.gerrit.acceptance.TestAccount;
+import com.google.gerrit.common.data.AccessSection;
+import com.google.gerrit.common.data.GlobalCapability;
+import com.google.gerrit.common.data.Permission;
+import com.google.gerrit.common.data.PermissionRule;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.server.account.GroupCache;
+import com.google.gerrit.server.config.AllProjectsName;
+import com.google.gerrit.server.git.MetaDataUpdate;
+import com.google.gerrit.server.git.ProjectConfig;
+import com.google.gerrit.server.project.ProjectCache;
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import com.google.inject.Inject;
+
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+
+public class CapabilitiesIT extends AbstractDaemonTest {
+
+  @Inject
+  private AccountCreator accounts;
+
+  @Inject
+  private AllProjectsName allProjects;
+
+  @Inject
+  private MetaDataUpdate.Server metaDataUpdateFactory;
+
+  @Inject
+  private GroupCache groupCache;
+
+  @Inject
+  private ProjectCache projectCache;
+
+  private RestSession userSession;
+  private RestSession adminSession;
+
+  @Before
+  public void setUp() throws Exception {
+    TestAccount user = accounts.create("user", "user@example.com", "User");
+    TestAccount admin = accounts.admin();
+    userSession = new RestSession(server, user);
+    adminSession = new RestSession(server, admin);
+  }
+
+  @Test
+  public void testCapabilitiesUser() throws IOException,
+      ConfigInvalidException, IllegalArgumentException,
+      IllegalAccessException, NoSuchFieldException,
+      SecurityException {
+    grantAllCapabilities();
+    RestResponse r =
+        userSession.get("/accounts/self/capabilities");
+    int code = r.getStatusCode();
+    assertEquals(code, 200);
+    CapabilityInfo info = (new Gson()).fromJson(r.getReader(),
+        new TypeToken<CapabilityInfo>() {}.getType());
+    for (String c: GlobalCapability.getAllNames()) {
+      if (GlobalCapability.ADMINISTRATE_SERVER.equals(c)) {
+        assertFalse(info.administrateServer);
+      } else if (GlobalCapability.PRIORITY.equals(c)) {
+        assertFalse(info.priority);
+      } else if (GlobalCapability.QUERY_LIMIT.equals(c)) {
+        assertEquals(0, info.queryLimit.min);
+        assertEquals(0, info.queryLimit.max);
+      } else {
+        assertTrue(String.format("capability %s was not granted", c),
+            (Boolean)CapabilityInfo.class.getField(c).get(info));
+      }
+    }
+  }
+
+  @Test
+  public void testCapabilitiesAdmin() throws IOException,
+      ConfigInvalidException, IllegalArgumentException,
+      IllegalAccessException, NoSuchFieldException,
+      SecurityException {
+    RestResponse r =
+        adminSession.get("/accounts/self/capabilities");
+    int code = r.getStatusCode();
+    assertEquals(code, 200);
+    CapabilityInfo info = (new Gson()).fromJson(r.getReader(),
+        new TypeToken<CapabilityInfo>() {}.getType());
+    for (String c: GlobalCapability.getAllNames()) {
+      if (GlobalCapability.PRIORITY.equals(c)) {
+        assertFalse(info.priority);
+      } else if (GlobalCapability.QUERY_LIMIT.equals(c)) {
+        assertEquals(0, info.queryLimit.min);
+        assertEquals(500, info.queryLimit.max);
+      } else if (GlobalCapability.ACCESS_DATABASE.equals(c)) {
+        assertFalse(info.accessDatabase);
+      } else if (GlobalCapability.RUN_AS.equals(c)) {
+        assertFalse(info.runAs);
+      } else {
+        assertTrue(String.format("capability %s was not granted", c),
+            (Boolean)CapabilityInfo.class.getField(c).get(info));
+      }
+    }
+  }
+
+  private void grantAllCapabilities() throws IOException,
+      ConfigInvalidException {
+    MetaDataUpdate md = metaDataUpdateFactory.create(allProjects);
+    md.setMessage("Make super user");
+    ProjectConfig config = ProjectConfig.read(md);
+    AccessSection s = config.getAccessSection(
+        AccessSection.GLOBAL_CAPABILITIES);
+    for (String c: GlobalCapability.getAllNames()) {
+      if (GlobalCapability.ADMINISTRATE_SERVER.equals(c)) {
+        continue;
+      }
+      Permission p = s.getPermission(c, true);
+      AccountGroup projectOwnersGroup = groupCache.get(
+          new AccountGroup.NameKey("Registered Users"));
+      PermissionRule rule = new PermissionRule(
+          config.resolve(projectOwnersGroup));
+      p.add(rule);
+    }
+    config.commit(md);
+    projectCache.evict(config.getProject());
+  }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/CapabilityInfo.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/CapabilityInfo.java
new file mode 100644
index 0000000..0586fe4
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/CapabilityInfo.java
@@ -0,0 +1,40 @@
+// 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.acceptance.rest.account;
+
+class CapabilityInfo {
+  public boolean accessDatabase;
+  public boolean administrateServer;
+  public boolean createAccount;
+  public boolean createGroup;
+  public boolean createProject;
+  public boolean emailReviewers;
+  public boolean flushCaches;
+  public boolean generateHttpPassword;
+  public boolean killTask;
+  public boolean priority;
+  public QueryLimit queryLimit;
+  public boolean runAs;
+  public boolean runGC;
+  public boolean streamEvents;
+  public boolean viewCaches;
+  public boolean viewConnections;
+  public boolean viewQueue;
+
+  static class QueryLimit {
+    short min;
+    short max;
+  }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/StarredChangesIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/StarredChangesIT.java
new file mode 100644
index 0000000..b5ae7de
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/StarredChangesIT.java
@@ -0,0 +1,122 @@
+// 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.acceptance.rest.account;
+
+import static com.google.gerrit.acceptance.git.GitUtil.cloneProject;
+import static com.google.gerrit.acceptance.git.GitUtil.createProject;
+import static com.google.gerrit.acceptance.git.GitUtil.initSsh;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.AccountCreator;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.acceptance.RestSession;
+import com.google.gerrit.acceptance.SshSession;
+import com.google.gerrit.acceptance.TestAccount;
+import com.google.gerrit.acceptance.git.PushOneCommit;
+import com.google.gerrit.acceptance.git.PushOneCommit.Result;
+import com.google.gerrit.acceptance.rest.change.ChangeInfo;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
+import com.google.inject.Inject;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.List;
+
+public class StarredChangesIT extends AbstractDaemonTest {
+
+  @Inject
+  private AccountCreator accounts;
+
+  @Inject
+  private SchemaFactory<ReviewDb> reviewDbProvider;
+
+  private TestAccount admin;
+
+  private RestSession session;
+  private Git git;
+  private ReviewDb db;
+
+  @Before
+  public void setUp() throws Exception {
+    admin = accounts.admin();
+    session = new RestSession(server, admin);
+    initSsh(admin);
+    Project.NameKey project = new Project.NameKey("p");
+    SshSession sshSession = new SshSession(server, admin);
+    createProject(sshSession, project.get());
+    git = cloneProject(sshSession.getUrl() + "/" + project.get());
+    sshSession.close();
+    db = reviewDbProvider.open();
+  }
+
+  @After
+  public void cleanup() {
+    db.close();
+  }
+
+  @Test
+  public void starredChangeState() throws GitAPIException, IOException,
+      OrmException {
+    Result c1 = createChange();
+    Result c2 = createChange();
+    assertNull(getChange(c1.getChangeId()).starred);
+    assertNull(getChange(c2.getChangeId()).starred);
+    starChange(true, c1.getPatchSetId().getParentKey());
+    starChange(true, c2.getPatchSetId().getParentKey());
+    assertTrue(getChange(c1.getChangeId()).starred);
+    assertTrue(getChange(c2.getChangeId()).starred);
+    starChange(false, c1.getPatchSetId().getParentKey());
+    starChange(false, c2.getPatchSetId().getParentKey());
+    assertNull(getChange(c1.getChangeId()).starred);
+    assertNull(getChange(c2.getChangeId()).starred);
+  }
+
+  private ChangeInfo getChange(String changeId) throws IOException {
+    RestResponse r = session.get("/changes/?q=" + changeId);
+    List<ChangeInfo> c = (new Gson()).fromJson(r.getReader(),
+        new TypeToken<List<ChangeInfo>>() {}.getType());
+    return c.get(0);
+  }
+
+  private void starChange(boolean on, Change.Id id) throws IOException {
+    String url = "/accounts/self/starred.changes/" + id.get();
+    if (on) {
+      RestResponse r = session.put(url);
+      assertEquals(204, r.getStatusCode());
+    } else {
+      RestResponse r = session.delete(url);
+      assertEquals(204, r.getStatusCode());
+    }
+  }
+
+  private Result createChange() throws GitAPIException, IOException {
+    PushOneCommit push = new PushOneCommit(db, admin.getIdent());
+    return push.to(git, "refs/for/master");
+  }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java
index fc2fccd..5e2c0d8 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java
@@ -28,6 +28,7 @@
 import com.google.gerrit.acceptance.TestAccount;
 import com.google.gerrit.acceptance.git.GitUtil;
 import com.google.gerrit.acceptance.git.PushOneCommit;
+import com.google.gerrit.extensions.api.changes.ReviewInput;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.client.Project.InheritableBoolean;
@@ -171,9 +172,9 @@
   }
 
   private void approve(String changeId) throws IOException {
-    RestResponse r =
-        session.post("/changes/" + changeId + "/revisions/current/review",
-            ReviewInput.approve());
+    RestResponse r = session.post(
+        "/changes/" + changeId + "/revisions/current/review",
+        new ReviewInput().label("Code-Review", 2));
     assertEquals(HttpStatus.SC_OK, r.getStatusCode());
     r.consume();
   }
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 b9c2d08..5172fa9 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
@@ -1,8 +1,26 @@
 include_defs('//gerrit-acceptance-tests/tests.defs')
 
+UTIL_SRCS = [
+  'AccountInfo.java',
+  'ChangeInfo.java',
+  'ChangeMessageInfo.java',
+  'GroupInfo.java',
+  'ProjectConfigInput.java',
+  'SubmitInput.java',
+  'SuggestReviewerInfo.java',
+]
+
+SUBMIT_UTIL_SRCS = [
+  'AbstractSubmit.java',
+  'AbstractSubmitByMerge.java',
+]
+
+NON_TEST = UTIL_SRCS + SUBMIT_UTIL_SRCS
+SUBMIT_TESTS = glob(['Submit*IT.java'], excludes = NON_TEST)
+OTHER_TESTS = glob(['*IT.java'], excludes = SUBMIT_TESTS + NON_TEST)
+
 acceptance_tests(
-  srcs = ['ChangeMessagesIT.java', 'DeleteDraftChangeIT.java',
-          'DeleteDraftPatchSetIT.java'],
+  srcs = OTHER_TESTS,
   deps = [
     ':util',
     '//gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git:util',
@@ -10,18 +28,16 @@
 )
 
 acceptance_tests(
-  srcs = ['SubmitByCherryPickIT.java', 'SubmitByFastForwardIT.java',
-          'SubmitByMergeAlwaysIT.java', 'SubmitByMergeIfNecessaryIT.java',
-          'SubmitByRebaseIfNecessaryIT.java'],
+  srcs = SUBMIT_TESTS,
   deps = [
-    ':submit',
+    ':submit_util',
     '//gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git:util',
   ],
 )
 
 java_library(
-  name = 'submit',
-  srcs = ['AbstractSubmit.java', 'AbstractSubmitByMerge.java'],
+  name = 'submit_util',
+  srcs = SUBMIT_UTIL_SRCS,
   deps = [
     ':util',
     '//gerrit-acceptance-tests:lib',
@@ -31,11 +47,10 @@
 
 java_library(
   name = 'util',
-  srcs = ['AccountInfo.java', 'ChangeInfo.java', 'ChangeMessageInfo.java',
-          'GroupInfo.java', 'ProjectConfigInput.java', 'ReviewInput.java',
-          'SubmitInput.java', 'SuggestReviewerInfo.java'],
+  srcs = UTIL_SRCS,
   deps = [
     '//lib:guava',
     '//gerrit-reviewdb:server',
   ],
+  visibility = ['//gerrit-acceptance-tests/...'],
 )
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeInfo.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeInfo.java
index fe8737e..8b431f0 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeInfo.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeInfo.java
@@ -24,4 +24,5 @@
   String branch;
   List<ChangeMessageInfo> messages;
   Change.Status status;
+  public Boolean starred;
 }
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ConflictsOperatorIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ConflictsOperatorIT.java
new file mode 100644
index 0000000..1472f38
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ConflictsOperatorIT.java
@@ -0,0 +1,152 @@
+// 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.acceptance.rest.change;
+
+import static com.google.gerrit.acceptance.git.GitUtil.checkout;
+import static com.google.gerrit.acceptance.git.GitUtil.cloneProject;
+import static com.google.gerrit.acceptance.git.GitUtil.initSsh;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.gerrit.acceptance.AbstractDaemonTestWithSecondaryIndex;
+import com.google.gerrit.acceptance.AccountCreator;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.acceptance.RestSession;
+import com.google.gerrit.acceptance.SshSession;
+import com.google.gerrit.acceptance.TestAccount;
+import com.google.gerrit.acceptance.git.GitUtil;
+import com.google.gerrit.acceptance.git.PushOneCommit;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import com.google.gwtorm.server.SchemaFactory;
+import com.google.inject.Inject;
+
+import com.jcraft.jsch.JSchException;
+
+import org.apache.http.HttpStatus;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.Set;
+
+public class ConflictsOperatorIT extends AbstractDaemonTestWithSecondaryIndex {
+
+  @Inject
+  private AccountCreator accounts;
+
+  @Inject
+  private SchemaFactory<ReviewDb> reviewDbProvider;
+
+  private TestAccount admin;
+  private RestSession session;
+  private Project.NameKey project;
+  private ReviewDb db;
+  private int count;
+
+  @Before
+  public void setUp() throws Exception {
+    admin = accounts.admin();
+    session = new RestSession(server, admin);
+    initSsh(admin);
+
+    project = new Project.NameKey("p");
+
+    db = reviewDbProvider.open();
+  }
+
+  @Test
+  public void noConflictingChanges() throws JSchException, IOException,
+      GitAPIException {
+    Git git = createProject();
+    PushOneCommit.Result change = createChange(git, true);
+    createChange(git, false);
+
+    Set<String> changes = queryConflictingChanges(change);
+    assertEquals(0, changes.size());
+  }
+
+  @Test
+  public void conflictingChanges() throws JSchException, IOException,
+      GitAPIException {
+    Git git = createProject();
+    PushOneCommit.Result change = createChange(git, true);
+    PushOneCommit.Result conflictingChange1 = createChange(git, true);
+    PushOneCommit.Result conflictingChange2 = createChange(git, true);
+    createChange(git, false);
+
+    Set<String> changes = queryConflictingChanges(change);
+    assertChanges(changes, conflictingChange1, conflictingChange2);
+  }
+
+  private Git createProject() throws JSchException, IOException,
+      GitAPIException {
+    SshSession sshSession = new SshSession(server, admin);
+    try {
+      GitUtil.createProject(sshSession, project.get(), null, true);
+      return cloneProject(sshSession.getUrl() + "/" + project.get());
+    } finally {
+      sshSession.close();
+    }
+  }
+
+  private PushOneCommit.Result createChange(Git git, boolean conflicting)
+      throws GitAPIException, IOException {
+    checkout(git, "origin/master");
+    String file = conflicting ? "test.txt" : "test-" + count + ".txt";
+    PushOneCommit push =
+        new PushOneCommit(db, admin.getIdent(), "Change " + count, file,
+            "content " + count);
+    count++;
+    return push.to(git, "refs/for/master");
+  }
+
+  private Set<String> queryConflictingChanges(PushOneCommit.Result change)
+      throws IOException {
+    RestResponse r =
+        session.get("/changes/?q=conflicts:" + change.getChangeId());
+    assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+    Set<ChangeInfo> changes =
+        (new Gson()).fromJson(r.getReader(),
+            new TypeToken<Set<ChangeInfo>>() {}.getType());
+    r.consume();
+    return ImmutableSet.copyOf(Iterables.transform(changes,
+        new Function<ChangeInfo, String>() {
+          @Override
+          public String apply(ChangeInfo input) {
+            return input.id;
+          }
+        }));
+  }
+
+  private void assertChanges(Set<String> actualChanges,
+      PushOneCommit.Result... expectedChanges) {
+    assertEquals(expectedChanges.length, actualChanges.size());
+    for (PushOneCommit.Result c : expectedChanges) {
+      assertTrue(actualChanges.contains(id(c)));
+    }
+  }
+
+  private String id(PushOneCommit.Result change) {
+    return project.get() + "~master~" + change.getChangeId();
+  }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SuggestReviewersIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SuggestReviewersIT.java
index 1ed4d61..8655b30 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SuggestReviewersIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/SuggestReviewersIT.java
@@ -97,7 +97,7 @@
   @GerritConfigs(
       {@GerritConfig(name = "suggest.accounts", value = "true"),
        @GerritConfig(name = "suggest.from", value = "1"),
-       @GerritConfig(name = "accounts.visibility", value = "NONE"),
+       @GerritConfig(name = "accounts.visibility", value = "NONE")
       })
   public void suggestReviewersNoResult2() throws GitAPIException, IOException,
       Exception {
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GarbageCollectionIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GarbageCollectionIT.java
index 7057a4f..69adedd 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GarbageCollectionIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GarbageCollectionIT.java
@@ -67,6 +67,7 @@
 
     project2 = new Project.NameKey("p2");
     createProject(sshSession, project2.get());
+    sshSession.close();
 
     session = new RestSession(server, admin);
   }
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetChildProjectIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetChildProjectIT.java
index bf8aac1b..e7440e8 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetChildProjectIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetChildProjectIT.java
@@ -74,6 +74,7 @@
     createProject(sshSession, p1.get());
     Project.NameKey p2 = new Project.NameKey("p2");
     createProject(sshSession, p2.get());
+    sshSession.close();
     assertEquals(HttpStatus.SC_NOT_FOUND,
         GET("/projects/" + p1.get() + "/children/" + p2.get()).getStatusCode());
   }
@@ -83,6 +84,7 @@
     SshSession sshSession = new SshSession(server, admin);
     Project.NameKey child = new Project.NameKey("p1");
     createProject(sshSession, child.get());
+    sshSession.close();
     RestResponse r = GET("/projects/" + allProjects.get() + "/children/" + child.get());
     assertEquals(HttpStatus.SC_OK, r.getStatusCode());
     ProjectInfo childInfo =
@@ -98,6 +100,7 @@
     createProject(sshSession, child.get());
     Project.NameKey grandChild = new Project.NameKey("p1.1");
     createProject(sshSession, grandChild.get(), child);
+    sshSession.close();
     assertEquals(HttpStatus.SC_NOT_FOUND,
         GET("/projects/" + allProjects.get() + "/children/" + grandChild.get())
             .getStatusCode());
@@ -111,6 +114,7 @@
     createProject(sshSession, child.get());
     Project.NameKey grandChild = new Project.NameKey("p1.1");
     createProject(sshSession, grandChild.get(), child);
+    sshSession.close();
     RestResponse r =
         GET("/projects/" + allProjects.get() + "/children/" + grandChild.get()
             + "?recursive");
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListBranchesIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListBranchesIT.java
index 4778662..69bbfda 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListBranchesIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListBranchesIT.java
@@ -99,6 +99,7 @@
 
   @After
   public void cleanup() {
+    sshSession.close();
     db.close();
   }
 
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListChildProjectsIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListChildProjectsIT.java
index c03ecd3..5feca06 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListChildProjectsIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListChildProjectsIT.java
@@ -84,6 +84,7 @@
     Project.NameKey child2 = new Project.NameKey("p2");
     createProject(sshSession, child2.get());
     createProject(sshSession, "p1.1", child1);
+    sshSession.close();
 
     RestResponse r = GET("/projects/" + allProjects.get() + "/children/");
     assertEquals(HttpStatus.SC_OK, r.getStatusCode());
@@ -107,6 +108,7 @@
     createProject(sshSession, child1_1_1.get(), child1_1);
     Project.NameKey child1_1_1_1 = new Project.NameKey("p1.1.1.1");
     createProject(sshSession, child1_1_1_1.get(), child1_1_1);
+    sshSession.close();
 
     RestResponse r = GET("/projects/" + child1.get() + "/children/?recursive");
     assertEquals(HttpStatus.SC_OK, r.getStatusCode());
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ProjectLevelConfigIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ProjectLevelConfigIT.java
new file mode 100644
index 0000000..9fd7568
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ProjectLevelConfigIT.java
@@ -0,0 +1,147 @@
+// 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.acceptance.rest.project;
+
+import static com.google.gerrit.acceptance.git.GitUtil.checkout;
+import static com.google.gerrit.acceptance.git.GitUtil.cloneProject;
+import static com.google.gerrit.acceptance.git.GitUtil.createProject;
+import static com.google.gerrit.acceptance.git.GitUtil.fetch;
+import static com.google.gerrit.acceptance.git.GitUtil.initSsh;
+import static org.junit.Assert.assertEquals;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.AccountCreator;
+import com.google.gerrit.acceptance.SshSession;
+import com.google.gerrit.acceptance.TestAccount;
+import com.google.gerrit.acceptance.git.PushOneCommit;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.config.AllProjectsNameProvider;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.project.ProjectCache;
+import com.google.gerrit.server.project.ProjectState;
+import com.google.gwtorm.server.SchemaFactory;
+import com.google.inject.Inject;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.lib.Config;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+
+public class ProjectLevelConfigIT extends AbstractDaemonTest {
+
+  @Inject
+  private AccountCreator accounts;
+
+  @Inject
+  private SchemaFactory<ReviewDb> reviewDbProvider;
+
+  @Inject
+  private ProjectCache projectCache;
+
+  @Inject
+  private AllProjectsNameProvider allProjects;
+
+  private ReviewDb db;
+  private TestAccount admin;
+  private SshSession sshSession;
+  private String project;
+  private Git git;
+
+  @Before
+  public void setUp() throws Exception {
+    admin = accounts.admin();
+    initSsh(admin);
+    sshSession = new SshSession(server, admin);
+
+    project = "p";
+    createProject(sshSession, project, null, true);
+    git = cloneProject(sshSession.getUrl() + "/" + project);
+    fetch(git, GitRepositoryManager.REF_CONFIG + ":refs/heads/config");
+    checkout(git, "refs/heads/config");
+
+    db = reviewDbProvider.open();
+  }
+
+  @After
+  public void cleanup() {
+    db.close();
+  }
+
+  @Test
+  public void accessProjectSpecificConfig() throws GitAPIException, IOException {
+    String configName = "test.config";
+    Config cfg = new Config();
+    cfg.setString("s1", null, "k1", "v1");
+    cfg.setString("s2", "ss", "k2", "v2");
+    PushOneCommit push =
+        new PushOneCommit(db, admin.getIdent(), "Create Project Level Config",
+            configName, cfg.toText());
+    push.to(git, GitRepositoryManager.REF_CONFIG);
+
+    ProjectState state = projectCache.get(new Project.NameKey(project));
+    assertEquals(cfg.toText(), state.getConfig(configName).get().toText());
+  }
+
+  @Test
+  public void nonExistingConfig() {
+    ProjectState state = projectCache.get(new Project.NameKey(project));
+    assertEquals("", state.getConfig("test.config").get().toText());
+  }
+
+  @Test
+  public void withInheritance() throws GitAPIException, IOException {
+    String configName = "test.config";
+
+    Config parentCfg = new Config();
+    parentCfg.setString("s1", null, "k1", "parentValue1");
+    parentCfg.setString("s1", null, "k2", "parentValue2");
+    parentCfg.setString("s2", "ss", "k3", "parentValue3");
+    parentCfg.setString("s2", "ss", "k4", "parentValue4");
+
+    Git parentGit =
+        cloneProject(sshSession.getUrl() + "/" + allProjects.get().get(), false);
+    fetch(parentGit, GitRepositoryManager.REF_CONFIG + ":refs/heads/config");
+    checkout(parentGit, "refs/heads/config");
+    PushOneCommit push =
+        new PushOneCommit(db, admin.getIdent(), "Create Project Level Config",
+            configName, parentCfg.toText());
+    push.to(parentGit, GitRepositoryManager.REF_CONFIG);
+
+    Config cfg = new Config();
+    cfg.setString("s1", null, "k1", "childValue1");
+    cfg.setString("s2", "ss", "k3", "childValue2");
+    push = new PushOneCommit(db, admin.getIdent(), "Create Project Level Config",
+        configName, cfg.toText());
+    push.to(git, GitRepositoryManager.REF_CONFIG);
+
+    ProjectState state = projectCache.get(new Project.NameKey(project));
+
+    Config expectedCfg = new Config();
+    expectedCfg.setString("s1", null, "k1", "childValue1");
+    expectedCfg.setString("s1", null, "k2", "parentValue2");
+    expectedCfg.setString("s2", "ss", "k3", "childValue2");
+    expectedCfg.setString("s2", "ss", "k4", "parentValue4");
+
+    assertEquals(expectedCfg.toText(), state.getConfig(configName)
+        .getWithInheritance().toText());
+
+    assertEquals(cfg.toText(), state.getConfig(configName).get().toText());
+  }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/GarbageCollectionIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/GarbageCollectionIT.java
index f10258c..24b9f51 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/GarbageCollectionIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/GarbageCollectionIT.java
@@ -35,6 +35,7 @@
 
 import com.jcraft.jsch.JSchException;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -83,6 +84,11 @@
     createProject(sshSession, project3.get());
   }
 
+  @After
+  public void cleanup() {
+    sshSession.close();
+  }
+
   @Test
   @UseLocalDisk
   public void testGc() throws JSchException, IOException {
@@ -110,6 +116,7 @@
     SshSession s = new SshSession(server, accounts.create("user", "user@example.com", "User"));
     s.exec("gerrit gc --all");
     assertError("Capability runGC is required to access this resource", s.getError());
+    s.close();
   }
 
   @Test
diff --git a/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/DefaultCacheFactory.java b/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/DefaultCacheFactory.java
index 1c850d1..4478cc9 100644
--- a/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/DefaultCacheFactory.java
+++ b/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/DefaultCacheFactory.java
@@ -27,7 +27,6 @@
 import com.google.gerrit.server.cache.PersistentCacheFactory;
 import com.google.gerrit.server.cache.h2.H2CacheImpl.ValueHolder;
 import com.google.gerrit.server.config.ConfigUtil;
-import com.google.gerrit.server.config.FactoryModule;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.inject.Inject;
 
@@ -39,13 +38,7 @@
   public static class Module extends LifecycleModule {
     @Override
     protected void configure() {
-      install(new FactoryModule() {
-        @Override
-        protected void configure() {
-          factory(ForwardingRemovalListener.Factory.class);
-        }
-      });
-
+      factory(ForwardingRemovalListener.Factory.class);
       bind(DefaultCacheFactory.class);
       bind(MemoryCacheFactory.class).to(DefaultCacheFactory.class);
       bind(PersistentCacheFactory.class).to(H2CacheFactory.class);
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 1f120ed7..4aca42b 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
@@ -28,6 +28,7 @@
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.sql.Timestamp;
+import java.sql.Types;
 import java.util.Calendar;
 import java.util.Map;
 import java.util.concurrent.ArrayBlockingQueue;
@@ -268,7 +269,7 @@
     }
 
     void set(PreparedStatement ps, int col, K value) throws SQLException {
-      ps.setObject(col, value);
+      ps.setObject(col, value, Types.JAVA_OBJECT);
     }
 
     Funnel<K> funnel() {
@@ -489,7 +490,7 @@
         }
         try {
           keyType.set(c.put, 1, key);
-          c.put.setObject(2, holder.value);
+          c.put.setObject(2, holder.value, Types.JAVA_OBJECT);
           c.put.setTimestamp(3, new Timestamp(holder.created));
           c.put.setTimestamp(4, TimeUtil.nowTs());
           c.put.executeUpdate();
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/changes/Side.java b/gerrit-common/src/main/java/com/google/gerrit/common/changes/Side.java
index 777467d..4a9ddf8 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/changes/Side.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/changes/Side.java
@@ -16,5 +16,5 @@
 
 /** The side on which a comment was added. */
 public enum Side {
-  PARENT, REVISION;
+  PARENT, REVISION
 }
\ No newline at end of file
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeListService.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeListService.java
deleted file mode 100644
index 0c466497..0000000
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeListService.java
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (C) 2008 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.common.data;
-
-import com.google.gerrit.common.audit.Audit;
-import com.google.gerrit.common.auth.SignInRequired;
-import com.google.gwtjsonrpc.common.AsyncCallback;
-import com.google.gwtjsonrpc.common.RemoteJsonService;
-import com.google.gwtjsonrpc.common.RpcImpl;
-import com.google.gwtjsonrpc.common.VoidResult;
-import com.google.gwtjsonrpc.common.RpcImpl.Version;
-
-@RpcImpl(version = Version.V2_0)
-public interface ChangeListService extends RemoteJsonService {
-  /**
-   * Add and/or remove changes from the set of starred changes of the caller.
-   *
-   * @param req the add and remove cluster.
-   */
-  @Audit
-  @SignInRequired
-  void toggleStars(ToggleStarRequest req, AsyncCallback<VoidResult> callback);
-}
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 69263d9..b5e2b2f 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
@@ -269,4 +269,24 @@
   public int hashCode() {
     return name.hashCode();
   }
+
+  @Override
+  public String toString() {
+    StringBuilder bldr = new StringBuilder();
+    bldr.append(name)
+        .append(" ");
+    if (exclusiveGroup) {
+      bldr.append("[exclusive] ");
+    }
+    bldr.append("[");
+    Iterator<PermissionRule> it = getRules().iterator();
+    while (it.hasNext()) {
+      bldr.append(it.next());
+      if (it.hasNext()) {
+        bldr.append(", ");
+      }
+    }
+    bldr.append("]");
+    return bldr.toString();
+  }
 }
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/PermissionRule.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/PermissionRule.java
index a7a66b1..bd05baf 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/PermissionRule.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/PermissionRule.java
@@ -20,7 +20,7 @@
   public static enum Action {
     ALLOW, DENY, BLOCK,
 
-    INTERACTIVE, BATCH;
+    INTERACTIVE, BATCH
   }
 
   protected Action action = Action.ALLOW;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAccess.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAccess.java
index ee6cc95..dd6c22b 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAccess.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAccess.java
@@ -28,6 +28,7 @@
   protected Set<String> ownerOf;
   protected boolean isConfigVisible;
   protected boolean canUpload;
+  protected boolean canChangeParent;
   protected LabelTypes labelTypes;
   protected Map<String, String> capabilities;
 
@@ -107,6 +108,14 @@
     this.canUpload = canUpload;
   }
 
+  public boolean canChangeParent() {
+    return canChangeParent;
+  }
+
+  public void setCanChangeParent(boolean canChangeParent) {
+    this.canChangeParent = canChangeParent;
+  }
+
   public LabelTypes getLabelTypes() {
     return labelTypes;
   }
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAdminService.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAdminService.java
index 44f60861..652acac 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAdminService.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAdminService.java
@@ -33,11 +33,11 @@
   @Audit
   @SignInRequired
   void changeProjectAccess(Project.NameKey projectName, String baseRevision,
-      String message, List<AccessSection> sections,
+      String message, List<AccessSection> sections, Project.NameKey parentProjectName,
       AsyncCallback<ProjectAccess> callback);
 
   @SignInRequired
   void reviewProjectAccess(Project.NameKey projectName, String baseRevision,
-      String message, List<AccessSection> sections,
+      String message, List<AccessSection> sections, Project.NameKey parentProjectName,
       AsyncCallback<Change.Id> callback);
 }
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ReviewerInfo.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ReviewerInfo.java
index 063f13b..28a8340 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ReviewerInfo.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ReviewerInfo.java
@@ -51,7 +51,7 @@
       if (accountInfo.getPreferredEmail() != null) {
         return accountInfo.getPreferredEmail();
       }
-      return accountInfo.getFullName().toString();
+      return accountInfo.getFullName();
     }
     return groupReference.getName();
   }
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/SubmitRecord.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/SubmitRecord.java
index 365f6a9..0d02fe0 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/SubmitRecord.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/SubmitRecord.java
@@ -37,7 +37,7 @@
      * <p>
      * Additional detail may be available in {@link SubmitRecord#errorMessage}.
      */
-    RULE_ERROR;
+    RULE_ERROR
   }
 
   public Status status;
@@ -78,7 +78,7 @@
        * The likely cause is access has not been granted correctly by the
        * project owner or site administrator.
        */
-      IMPOSSIBLE;
+      IMPOSSIBLE
     }
 
     public String label;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/errors/UpdateParentFailedException.java b/gerrit-common/src/main/java/com/google/gerrit/common/errors/UpdateParentFailedException.java
new file mode 100644
index 0000000..320d055
--- /dev/null
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/errors/UpdateParentFailedException.java
@@ -0,0 +1,27 @@
+// 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.common.errors;
+
+/** Error indicating that updating a parent project failed. */
+public class UpdateParentFailedException extends Exception {
+  private static final long serialVersionUID = 1L;
+
+  public static final String MESSAGE = "Update Parent Project Failed: ";
+
+  public UpdateParentFailedException(final String message,
+      final Throwable why) {
+    super(MESSAGE + ": " + message, why);
+  }
+}
diff --git a/gerrit-common/src/test/java/com/google/gerrit/common/data/EncodePathSeparatorTest.java b/gerrit-common/src/test/java/com/google/gerrit/common/data/EncodePathSeparatorTest.java
index e00fa48..7c662ae 100644
--- a/gerrit-common/src/test/java/com/google/gerrit/common/data/EncodePathSeparatorTest.java
+++ b/gerrit-common/src/test/java/com/google/gerrit/common/data/EncodePathSeparatorTest.java
@@ -14,10 +14,12 @@
 
 package com.google.gerrit.common.data;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
 
-public class EncodePathSeparatorTest extends TestCase {
+public class EncodePathSeparatorTest {
 
+  @Test
   public void testDefaultBehaviour() {
 
     GitWebType gitWebType = GitWebType.fromName(null);
@@ -25,6 +27,7 @@
     assertEquals("a/b", gitWebType.replacePathSeparator("a/b"));
   }
 
+  @Test
   public void testExclamationMark() {
 
     GitWebType gitWebType = GitWebType.fromName(null);
diff --git a/gerrit-common/src/test/java/com/google/gerrit/common/data/ParameterizedStringTest.java b/gerrit-common/src/test/java/com/google/gerrit/common/data/ParameterizedStringTest.java
index a2d1279..5000211 100644
--- a/gerrit-common/src/test/java/com/google/gerrit/common/data/ParameterizedStringTest.java
+++ b/gerrit-common/src/test/java/com/google/gerrit/common/data/ParameterizedStringTest.java
@@ -14,12 +14,17 @@
 
 package com.google.gerrit.common.data;
 
-import junit.framework.TestCase;
+import org.junit.Test;
 
 import java.util.HashMap;
 import java.util.Map;
 
-public class ParameterizedStringTest extends TestCase {
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class ParameterizedStringTest {
+  @Test
   public void testEmptyString() {
     final ParameterizedString p = new ParameterizedString("");
     assertEquals("", p.getPattern());
@@ -32,6 +37,7 @@
     assertEquals("", p.replace(a));
   }
 
+  @Test
   public void testAsis1() {
     final ParameterizedString p = ParameterizedString.asis("${bar}c");
     assertEquals("${bar}c", p.getPattern());
@@ -45,6 +51,7 @@
     assertEquals("${bar}c", p.replace(a));
   }
 
+  @Test
   public void testReplace1() {
     final ParameterizedString p = new ParameterizedString("${bar}c");
     assertEquals("${bar}c", p.getPattern());
@@ -60,6 +67,7 @@
     assertEquals("frobinatorc", p.replace(a));
   }
 
+  @Test
   public void testReplace2() {
     final ParameterizedString p = new ParameterizedString("a${bar}c");
     assertEquals("a${bar}c", p.getPattern());
@@ -75,6 +83,7 @@
     assertEquals("afrobinatorc", p.replace(a));
   }
 
+  @Test
   public void testReplace3() {
     final ParameterizedString p = new ParameterizedString("a${bar}");
     assertEquals("a${bar}", p.getPattern());
@@ -90,6 +99,7 @@
     assertEquals("afrobinator", p.replace(a));
   }
 
+  @Test
   public void testReplace4() {
     final ParameterizedString p = new ParameterizedString("a${bar}c");
     assertEquals("a${bar}c", p.getPattern());
@@ -104,6 +114,7 @@
     assertEquals("ac", p.replace(a));
   }
 
+  @Test
   public void testReplaceToLowerCase() {
     final ParameterizedString p = new ParameterizedString("${a.toLowerCase}");
     assertEquals(1, p.getParameterNames().size());
@@ -124,6 +135,7 @@
     assertEquals("foo", p.replace(a));
   }
 
+  @Test
   public void testReplaceToUpperCase() {
     final ParameterizedString p = new ParameterizedString("${a.toUpperCase}");
     assertEquals(1, p.getParameterNames().size());
@@ -144,6 +156,7 @@
     assertEquals("FOO", p.replace(a));
   }
 
+  @Test
   public void testReplaceLocalName() {
     final ParameterizedString p = new ParameterizedString("${a.localPart}");
     assertEquals(1, p.getParameterNames().size());
@@ -164,6 +177,7 @@
     assertEquals("foo", p.replace(a));
   }
 
+  @Test
   public void testUndefinedFunctionName() {
     ParameterizedString p =
         new ParameterizedString(
@@ -183,6 +197,7 @@
     assertEquals("hi, FIRSTNAME LASTNAME,your eamil address is 'firstname.lastname'.right?", p.replace(a));
   }
 
+  @Test
   public void testReplaceToUpperCaseToLowerCase() {
     final ParameterizedString p =
         new ParameterizedString("${a.toUpperCase.toLowerCase}");
@@ -204,6 +219,7 @@
     assertEquals("foo@example.com", p.replace(a));
   }
 
+  @Test
   public void testReplaceToUpperCaseLocalName() {
     final ParameterizedString p =
         new ParameterizedString("${a.toUpperCase.localPart}");
@@ -225,6 +241,7 @@
     assertEquals("FOO", p.replace(a));
   }
 
+  @Test
   public void testReplaceToUpperCaseAnUndefinedMethod() {
     final ParameterizedString p =
         new ParameterizedString("${a.toUpperCase.anUndefinedMethod}");
@@ -246,6 +263,7 @@
     assertEquals("FOO@EXAMPLE.COM", p.replace(a));
   }
 
+  @Test
   public void testReplaceLocalNameToUpperCase() {
     final ParameterizedString p =
         new ParameterizedString("${a.localPart.toUpperCase}");
@@ -267,6 +285,7 @@
     assertEquals("FOO", p.replace(a));
   }
 
+  @Test
   public void testReplaceLocalNameToLowerCase() {
     final ParameterizedString p =
         new ParameterizedString("${a.localPart.toLowerCase}");
@@ -288,6 +307,7 @@
     assertEquals("foo", p.replace(a));
   }
 
+  @Test
   public void testReplaceLocalNameAnUndefinedMethod() {
     final ParameterizedString p =
         new ParameterizedString("${a.localPart.anUndefinedMethod}");
@@ -309,6 +329,7 @@
     assertEquals("foo", p.replace(a));
   }
 
+  @Test
   public void testReplaceToLowerCaseToUpperCase() {
     final ParameterizedString p =
         new ParameterizedString("${a.toLowerCase.toUpperCase}");
@@ -330,6 +351,7 @@
     assertEquals("FOO@EXAMPLE.COM", p.replace(a));
   }
 
+  @Test
   public void testReplaceToLowerCaseLocalName() {
     final ParameterizedString p =
         new ParameterizedString("${a.toLowerCase.localPart}");
@@ -351,6 +373,7 @@
     assertEquals("foo", p.replace(a));
   }
 
+  @Test
   public void testReplaceToLowerCaseAnUndefinedMethod() {
     final ParameterizedString p =
         new ParameterizedString("${a.toLowerCase.anUndefinedMethod}");
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/annotations/CapabilityScope.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/annotations/CapabilityScope.java
index ede8b8c..85f7d15 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/annotations/CapabilityScope.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/annotations/CapabilityScope.java
@@ -32,5 +32,5 @@
   PLUGIN,
 
   /** Scope is the core server. */
-  CORE;
+  CORE
 }
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/GerritApi.java
similarity index 63%
copy from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
copy to gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/GerritApi.java
index a5371d2..bde58995 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/GerritApi.java
@@ -12,19 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.acceptance.rest.change;
+package com.google.gerrit.extensions.api;
 
-import com.google.common.collect.Maps;
+import com.google.gerrit.extensions.api.changes.Changes;
 
-import java.util.Map;
-
-public class ReviewInput {
-  Map<String, Integer> labels;
-
-  public static ReviewInput approve() {
-    ReviewInput in = new ReviewInput();
-    in.labels = Maps.newHashMap();
-    in.labels.put("Code-Review", 2);
-    return in;
-  }
+public interface GerritApi {
+  public Changes changes();
 }
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/AbandonInput.java
similarity index 63%
copy from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
copy to gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/AbandonInput.java
index a5371d2..04a7bc7 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/AbandonInput.java
@@ -12,19 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.acceptance.rest.change;
+package com.google.gerrit.extensions.api.changes;
 
-import com.google.common.collect.Maps;
+import com.google.gerrit.extensions.restapi.DefaultInput;
 
-import java.util.Map;
-
-public class ReviewInput {
-  Map<String, Integer> labels;
-
-  public static ReviewInput approve() {
-    ReviewInput in = new ReviewInput();
-    in.labels = Maps.newHashMap();
-    in.labels.put("Code-Review", 2);
-    return in;
-  }
+public class AbandonInput {
+  @DefaultInput
+  public String message;
 }
+
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
new file mode 100644
index 0000000..a264009
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
@@ -0,0 +1,34 @@
+// 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.extensions.api.changes;
+
+import com.google.gerrit.extensions.restapi.RestApiException;
+
+public interface ChangeApi {
+  String id();
+
+  RevisionApi current() throws RestApiException;
+  RevisionApi revision(int id) throws RestApiException;
+  RevisionApi revision(String id) throws RestApiException;
+
+  void abandon() throws RestApiException;
+  void abandon(AbandonInput in) throws RestApiException;
+
+  void restore() throws RestApiException;
+  void restore(RestoreInput in) throws RestApiException;
+
+  ChangeApi revert() throws RestApiException;
+  ChangeApi revert(RevertInput in) throws RestApiException;
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/Changes.java
similarity index 63%
copy from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
copy to gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/Changes.java
index a5371d2..48e9fd3 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/Changes.java
@@ -12,19 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.acceptance.rest.change;
+package com.google.gerrit.extensions.api.changes;
 
-import com.google.common.collect.Maps;
+import com.google.gerrit.extensions.restapi.RestApiException;
 
-import java.util.Map;
-
-public class ReviewInput {
-  Map<String, Integer> labels;
-
-  public static ReviewInput approve() {
-    ReviewInput in = new ReviewInput();
-    in.labels = Maps.newHashMap();
-    in.labels.put("Code-Review", 2);
-    return in;
-  }
+public interface Changes {
+  ChangeApi id(int id) throws RestApiException;
+  ChangeApi id(String triplet) throws RestApiException;
+  ChangeApi id(String project, String branch, String id)
+      throws RestApiException;
 }
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RestoreInput.java
similarity index 63%
copy from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
copy to gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RestoreInput.java
index a5371d2..a116dde 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RestoreInput.java
@@ -12,19 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.acceptance.rest.change;
+package com.google.gerrit.extensions.api.changes;
 
-import com.google.common.collect.Maps;
+import com.google.gerrit.extensions.restapi.DefaultInput;
 
-import java.util.Map;
-
-public class ReviewInput {
-  Map<String, Integer> labels;
-
-  public static ReviewInput approve() {
-    ReviewInput in = new ReviewInput();
-    in.labels = Maps.newHashMap();
-    in.labels.put("Code-Review", 2);
-    return in;
-  }
+public class RestoreInput {
+  @DefaultInput
+  public String message;
 }
+
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevertInput.java
similarity index 63%
copy from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
copy to gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevertInput.java
index a5371d2..2c1c688 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevertInput.java
@@ -12,19 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.acceptance.rest.change;
+package com.google.gerrit.extensions.api.changes;
 
-import com.google.common.collect.Maps;
+import com.google.gerrit.extensions.restapi.DefaultInput;
 
-import java.util.Map;
-
-public class ReviewInput {
-  Map<String, Integer> labels;
-
-  public static ReviewInput approve() {
-    ReviewInput in = new ReviewInput();
-    in.labels = Maps.newHashMap();
-    in.labels.put("Code-Review", 2);
-    return in;
-  }
+public class RevertInput {
+  @DefaultInput
+  public String message;
 }
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
new file mode 100644
index 0000000..969c23d
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ReviewInput.java
@@ -0,0 +1,116 @@
+// 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.extensions.api.changes;
+
+import com.google.gerrit.extensions.restapi.DefaultInput;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/** Input passed to {@code POST /changes/{id}/revisions/{id}/review}. */
+public class ReviewInput {
+  @DefaultInput
+  public String message;
+
+  public Map<String, Short> labels;
+  public Map<String, List<Comment>> comments;
+
+  /**
+   * If true require all labels to be within the user's permitted ranges based
+   * on access controls, attempting to use a label not granted to the user
+   * will fail the entire modify operation early. If false the operation will
+   * execute anyway, but the proposed labels given by the user will be
+   * modified to be the "best" value allowed by the access controls, or
+   * ignored if the label does not exist.
+   */
+  public boolean strictLabels = true;
+
+  /**
+   * How to process draft comments already in the database that were not also
+   * described in this input request.
+   */
+  public DraftHandling drafts = DraftHandling.DELETE;
+
+  /** Who to send email notifications to after review is stored. */
+  public NotifyHandling notify = NotifyHandling.ALL;
+
+  /**
+   * Account ID, name, email address or username of another user. The review
+   * will be posted/updated on behalf of this named user instead of the
+   * caller. Caller must have the labelAs-$NAME permission granted for each
+   * label that appears in {@link #labels}. This is in addition to the named
+   * user also needing to have permission to use the labels.
+   * <p>
+   * {@link #strictLabels} impacts how labels is processed for the named user,
+   * not the caller.
+   */
+  public String onBehalfOf;
+
+  public static enum DraftHandling {
+    DELETE, PUBLISH, KEEP;
+  }
+
+  public static enum NotifyHandling {
+    NONE, OWNER, OWNER_REVIEWERS, ALL;
+  }
+
+  public static enum Side {
+    PARENT, REVISION;
+  }
+
+  public static class Comment {
+    public String id;
+    public Side side;
+    public int line;
+    public String inReplyTo;
+    public String message;
+    public Range range;
+
+    public static class Range {
+      public int startLine;
+      public int startCharacter;
+      public int endLine;
+      public int endCharacter;
+    }
+  }
+
+  public ReviewInput message(String msg) {
+    message = msg != null && !msg.isEmpty() ? msg : null;
+    return this;
+  }
+
+  public ReviewInput label(String name, short value) {
+    if (name == null || name.isEmpty()) {
+      throw new IllegalArgumentException();
+    }
+    if (labels == null) {
+      labels = new LinkedHashMap<String, Short>(4);
+    }
+    labels.put(name, value);
+    return this;
+  }
+
+  public ReviewInput label(String name, int value) {
+    if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
+      throw new IllegalArgumentException();
+    }
+    return label(name, (short) value);
+  }
+
+  public ReviewInput label(String name) {
+    return label(name, (short) 1);
+  }
+}
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
new file mode 100644
index 0000000..ff4a94e
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
@@ -0,0 +1,27 @@
+// 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.extensions.api.changes;
+
+import com.google.gerrit.extensions.restapi.RestApiException;
+
+public interface RevisionApi {
+  void delete() throws RestApiException;
+  void rebase() throws RestApiException;
+  void review(ReviewInput in) throws RestApiException;
+
+  /** {@code submit} with {@link SubmitInput#waitForMerge} set to true. */
+  void submit() throws RestApiException;
+  void submit(SubmitInput in) throws RestApiException;
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/SubmitInput.java
similarity index 63%
copy from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
copy to gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/SubmitInput.java
index a5371d2..91e3c70 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/SubmitInput.java
@@ -12,19 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.acceptance.rest.change;
+package com.google.gerrit.extensions.api.changes;
 
-import com.google.common.collect.Maps;
-
-import java.util.Map;
-
-public class ReviewInput {
-  Map<String, Integer> labels;
-
-  public static ReviewInput approve() {
-    ReviewInput in = new ReviewInput();
-    in.labels = Maps.newHashMap();
-    in.labels.put("Code-Review", 2);
-    return in;
-  }
+public class SubmitInput {
+  public boolean waitForMerge;
 }
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/config/DownloadScheme.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/config/DownloadScheme.java
index 20eda97..d81657a 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/config/DownloadScheme.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/config/DownloadScheme.java
@@ -30,9 +30,7 @@
   public abstract boolean isAuthRequired();
 
   /** @return whether this scheme supports authentication */
-  public boolean isAuthSupported() {
-    return isAuthRequired();
-  }
+  public abstract boolean isAuthSupported();
 
   /** @return whether the download scheme is enabled */
   public abstract boolean isEnabled();
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/CacheControl.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/CacheControl.java
index 72f1bc5..3aa1781 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/CacheControl.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/CacheControl.java
@@ -19,7 +19,7 @@
 public class CacheControl {
 
   public enum Type {
-    NONE, PUBLIC, PRIVATE;
+    NONE, PUBLIC, PRIVATE
   }
 
   public static final CacheControl NONE = new CacheControl(Type.NONE, 0, null);
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/RestApiException.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/RestApiException.java
index 3fae128..b6ba730 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/RestApiException.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/RestApiException.java
@@ -15,7 +15,7 @@
 package com.google.gerrit.extensions.restapi;
 
 /** Root exception type for JSON API failures. */
-public abstract class RestApiException extends Exception {
+public class RestApiException extends Exception {
   private static final long serialVersionUID = 1L;
   private CacheControl caching = CacheControl.NONE;
 
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/systemstatus/ServerInformation.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/systemstatus/ServerInformation.java
index 3d2df21..c7deedb 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/systemstatus/ServerInformation.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/systemstatus/ServerInformation.java
@@ -35,7 +35,7 @@
      * The server is attempting a graceful halt of operations and will exit (or
      * be killed by the operating system) soon.
      */
-    SHUTDOWN;
+    SHUTDOWN
   }
 
   State getState();
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/TopMenu.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/TopMenu.java
index 7389519fc..e5a1f7e 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/TopMenu.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/TopMenu.java
@@ -38,15 +38,21 @@
     public final String url;
     public final String name;
     public final String target;
+    public final String id;
 
     public MenuItem(String name, String url) {
       this(name, url, "_blank");
     }
 
     public MenuItem(String name, String url, String target) {
+      this(name, url, target, null);
+    }
+
+    public MenuItem(String name, String url, String target, String id) {
       this.url = url;
       this.name = name;
       this.target = target;
+      this.id = id;
     }
   }
 
diff --git a/gerrit-gwtdebug/src/main/java/com/google/gerrit/gwtdebug/GerritDebugLauncher.java b/gerrit-gwtdebug/src/main/java/com/google/gerrit/gwtdebug/GerritDebugLauncher.java
index a2a770e..5770f58 100644
--- a/gerrit-gwtdebug/src/main/java/com/google/gerrit/gwtdebug/GerritDebugLauncher.java
+++ b/gerrit-gwtdebug/src/main/java/com/google/gerrit/gwtdebug/GerritDebugLauncher.java
@@ -368,7 +368,7 @@
 
     AbstractConnector connector = getConnector();
     if (bindAddress != null) {
-      connector.setHost(bindAddress.toString());
+      connector.setHost(bindAddress);
     }
     connector.setPort(port);
 
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 ba4f626..032db65 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
@@ -24,6 +24,7 @@
   public static final int M_CTRL = 1 << 16;
   public static final int M_ALT = 2 << 16;
   public static final int M_META = 4 << 16;
+  public static final int M_SHIFT = 8 << 16;
 
   public static boolean same(final KeyCommand a, final KeyCommand b) {
     return a.getClass() == b.getClass() && a.helpText.equals(b.helpText);
@@ -58,6 +59,9 @@
     if ((keyMask & M_META) == M_META) {
       modifier(b, KeyConstants.I.keyMeta());
     }
+    if ((keyMask & M_SHIFT) == M_SHIFT) {
+      modifier(b, KeyConstants.I.keyShift());
+    }
 
     final char c = (char) (keyMask & 0xffff);
     switch (c) {
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 56fb85c..b4cb41e 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
@@ -32,6 +32,7 @@
   String keyCtrl();
   String keyAlt();
   String keyMeta();
+  String keyShift();
   String keyEnter();
   String keyEsc();
 }
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 e21daf5..2e12b07 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
@@ -10,5 +10,6 @@
 keyCtrl = Ctrl
 keyAlt = Alt
 keyMeta = Meta
+keyShift = Shift
 keyEnter = Enter
 keyEsc = Esc
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/progress/client/ProgressBar.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/progress/client/ProgressBar.java
index 5e13f55..931e84e 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/progress/client/ProgressBar.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/progress/client/ProgressBar.java
@@ -71,7 +71,7 @@
   public void setValue(final int pComplete) {
     assert 0 <= pComplete && pComplete <= 100;
     value = pComplete;
-    bar.setWidth("" + (2 * pComplete) + "px");
+    bar.setWidth(2 * pComplete + "px");
     msg.setText(callerText + pComplete + "%");
   }
 }
diff --git a/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/LinkFindReplaceTest.java b/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/LinkFindReplaceTest.java
index 97f816f..0d8336e 100644
--- a/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/LinkFindReplaceTest.java
+++ b/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/LinkFindReplaceTest.java
@@ -15,10 +15,15 @@
 package com.google.gwtexpui.safehtml.client;
 
 import static com.google.gwtexpui.safehtml.client.LinkFindReplace.hasValidScheme;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
-import junit.framework.TestCase;
+import org.junit.Test;
 
-public class LinkFindReplaceTest extends TestCase {
+public class LinkFindReplaceTest {
+  @Test
   public void testNoEscaping() {
     String find = "find";
     String link = "link";
@@ -28,12 +33,14 @@
     assertEquals("find = " + find + ", link = " + link, a.toString());
   }
 
+  @Test
   public void testBackreference() {
     assertEquals("<a href=\"/bug?id=123\">issue 123</a>",
         new LinkFindReplace("(bug|issue)\\s*([0-9]+)", "/bug?id=$2")
             .replace("issue 123"));
   }
 
+  @Test
   public void testHasValidScheme() {
     assertTrue(hasValidScheme("/absolute/path"));
     assertTrue(hasValidScheme("relative/path"));
@@ -46,6 +53,7 @@
     assertFalse(hasValidScheme("javascript:alert(1)"));
   }
 
+  @Test
   public void testInvalidSchemeInReplace() {
     try {
       new LinkFindReplace("find", "javascript:alert(1)").replace("find");
@@ -54,6 +62,7 @@
     }
   }
 
+  @Test
   public void testInvalidSchemeWithBackreference() {
     try {
       new LinkFindReplace(".*(script:[^;]*)", "java$1")
@@ -63,11 +72,13 @@
     }
   }
 
+  @Test
   public void testReplaceEscaping() {
     assertEquals("<a href=\"a&quot;&amp;&#39;&lt;&gt;b\">find</a>",
         new LinkFindReplace("find", "a\"&'<>b").replace("find"));
   }
 
+  @Test
   public void testHtmlInFind() {
     String rawFind = "<b>&quot;bold&quot;</b>";
     LinkFindReplace a = new LinkFindReplace(rawFind, "/bold");
diff --git a/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/RawFindReplaceTest.java b/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/RawFindReplaceTest.java
index 9c450bd..bc20a9d 100644
--- a/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/RawFindReplaceTest.java
+++ b/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/RawFindReplaceTest.java
@@ -14,9 +14,11 @@
 
 package com.google.gwtexpui.safehtml.client;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
 
-public class RawFindReplaceTest extends TestCase {
+public class RawFindReplaceTest {
+  @Test
   public void testFindReplace() {
     final String find = "find";
     final String replace = "replace";
diff --git a/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtmlBuilderTest.java b/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtmlBuilderTest.java
index a6b0012..0163d7f 100644
--- a/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtmlBuilderTest.java
+++ b/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtmlBuilderTest.java
@@ -14,9 +14,18 @@
 
 package com.google.gwtexpui.safehtml.client;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
-public class SafeHtmlBuilderTest extends TestCase {
+import org.junit.Test;
+
+public class SafeHtmlBuilderTest {
+  @Test
   public void testEmpty() {
     final SafeHtmlBuilder b = new SafeHtmlBuilder();
     assertTrue(b.isEmpty());
@@ -28,6 +37,7 @@
     assertEquals("a", b.asString());
   }
 
+  @Test
   public void testToSafeHtml() {
     final SafeHtmlBuilder b = new SafeHtmlBuilder();
     b.append(1);
@@ -39,6 +49,7 @@
     assertEquals("1", h.asString());
   }
 
+  @Test
   public void testAppend_boolean() {
     final SafeHtmlBuilder b = new SafeHtmlBuilder();
     assertSame(b, b.append(true));
@@ -46,6 +57,7 @@
     assertEquals("truefalse", b.asString());
   }
 
+  @Test
   public void testAppend_char() {
     final SafeHtmlBuilder b = new SafeHtmlBuilder();
     assertSame(b, b.append('a'));
@@ -53,6 +65,7 @@
     assertEquals("ab", b.asString());
   }
 
+  @Test
   public void testAppend_int() {
     final SafeHtmlBuilder b = new SafeHtmlBuilder();
     assertSame(b, b.append(4));
@@ -61,6 +74,7 @@
     assertEquals("42-100", b.asString());
   }
 
+  @Test
   public void testAppend_long() {
     final SafeHtmlBuilder b = new SafeHtmlBuilder();
     assertSame(b, b.append(4L));
@@ -68,18 +82,21 @@
     assertEquals("42", b.asString());
   }
 
+  @Test
   public void testAppend_float() {
     final SafeHtmlBuilder b = new SafeHtmlBuilder();
     assertSame(b, b.append(0.0f));
     assertEquals("0.0", b.asString());
   }
 
+  @Test
   public void testAppend_double() {
     final SafeHtmlBuilder b = new SafeHtmlBuilder();
     assertSame(b, b.append(0.0));
     assertEquals("0.0", b.asString());
   }
 
+  @Test
   public void testAppend_String() {
     final SafeHtmlBuilder b = new SafeHtmlBuilder();
     assertSame(b, b.append((String) null));
@@ -89,6 +106,7 @@
     assertEquals("foobar", b.asString());
   }
 
+  @Test
   public void testAppend_StringBuilder() {
     final SafeHtmlBuilder b = new SafeHtmlBuilder();
     assertSame(b, b.append((StringBuilder) null));
@@ -98,6 +116,7 @@
     assertEquals("foobar", b.asString());
   }
 
+  @Test
   public void testAppend_StringBuffer() {
     final SafeHtmlBuilder b = new SafeHtmlBuilder();
     assertSame(b, b.append((StringBuffer) null));
@@ -107,6 +126,7 @@
     assertEquals("foobar", b.asString());
   }
 
+  @Test
   public void testAppend_Object() {
     final SafeHtmlBuilder b = new SafeHtmlBuilder();
     assertSame(b, b.append((Object) null));
@@ -120,6 +140,7 @@
     assertEquals("foobar", b.asString());
   }
 
+  @Test
   public void testAppend_CharSequence() {
     final SafeHtmlBuilder b = new SafeHtmlBuilder();
     assertSame(b, b.append((CharSequence) null));
@@ -129,6 +150,7 @@
     assertEquals("foobar", b.asString());
   }
 
+  @Test
   public void testAppend_SafeHtml() {
     final SafeHtmlBuilder b = new SafeHtmlBuilder();
     assertSame(b, b.append((SafeHtml) null));
@@ -138,6 +160,7 @@
     assertEquals("foobar", b.asString());
   }
 
+  @Test
   public void testHtmlSpecialCharacters() {
     assertEquals("&amp;", escape("&"));
     assertEquals("&lt;", escape("<"));
@@ -155,18 +178,21 @@
     assertEquals("&amp;lt;b&amp;gt;", escape("&lt;b&gt;"));
   }
 
+  @Test
   public void testEntityNbsp() {
     final SafeHtmlBuilder b = new SafeHtmlBuilder();
     assertSame(b, b.nbsp());
     assertEquals("&nbsp;", b.asString());
   }
 
+  @Test
   public void testTagBr() {
     final SafeHtmlBuilder b = new SafeHtmlBuilder();
     assertSame(b, b.br());
     assertEquals("<br />", b.asString());
   }
 
+  @Test
   public void testTagTableTrTd() {
     final SafeHtmlBuilder b = new SafeHtmlBuilder();
     assertSame(b, b.openElement("table"));
@@ -179,6 +205,7 @@
     assertEquals("<table><tr><td>d&lt;a&gt;ta</td></tr></table>", b.asString());
   }
 
+  @Test
   public void testTagDiv() {
     final SafeHtmlBuilder b = new SafeHtmlBuilder();
     assertSame(b, b.openDiv());
@@ -187,6 +214,7 @@
     assertEquals("<div>d&lt;a&gt;ta</div>", b.asString());
   }
 
+  @Test
   public void testTagAnchor() {
     final SafeHtmlBuilder b = new SafeHtmlBuilder();
     assertSame(b, b.openAnchor());
@@ -206,6 +234,7 @@
     assertEquals("<a href=\"d&lt;a&gt;ta\">go</a>", b.asString());
   }
 
+  @Test
   public void testTagHeightWidth() {
     final SafeHtmlBuilder b = new SafeHtmlBuilder();
     assertSame(b, b.openElement("img"));
@@ -215,6 +244,7 @@
     assertEquals("<img height=\"100\" width=\"42\" />", b.asString());
   }
 
+  @Test
   public void testStyleName() {
     final SafeHtmlBuilder b = new SafeHtmlBuilder();
     assertSame(b, b.openSpan());
@@ -225,6 +255,7 @@
     assertEquals("<span class=\"foo bar\">d&lt;a&gt;ta</span>", b.asString());
   }
 
+  @Test
   public void testRejectJavaScript_AnchorHref() {
     final String href = "javascript:window.close();";
     try {
@@ -235,6 +266,7 @@
     }
   }
 
+  @Test
   public void testRejectJavaScript_ImgSrc() {
     final String href = "javascript:window.close();";
     try {
@@ -245,6 +277,7 @@
     }
   }
 
+  @Test
   public void testRejectJavaScript_FormAction() {
     final String href = "javascript:window.close();";
     try {
diff --git a/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_LinkifyTest.java b/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_LinkifyTest.java
index a9d9450..749df17 100644
--- a/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_LinkifyTest.java
+++ b/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_LinkifyTest.java
@@ -14,9 +14,13 @@
 
 package com.google.gwtexpui.safehtml.client;
 
-import junit.framework.TestCase;
+import org.junit.Test;
 
-public class SafeHtml_LinkifyTest extends TestCase {
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+
+public class SafeHtml_LinkifyTest {
+  @Test
   public void testLinkify_SimpleHttp1() {
     final SafeHtml o = html("A http://go.here/ B");
     final SafeHtml n = o.linkify();
@@ -24,6 +28,7 @@
     assertEquals("A <a href=\"http://go.here/\" target=\"_blank\">http://go.here/</a> B", n.asString());
   }
 
+  @Test
   public void testLinkify_SimpleHttps2() {
     final SafeHtml o = html("A https://go.here/ B");
     final SafeHtml n = o.linkify();
@@ -31,6 +36,7 @@
     assertEquals("A <a href=\"https://go.here/\" target=\"_blank\">https://go.here/</a> B", n.asString());
   }
 
+  @Test
   public void testLinkify_Parens1() {
     final SafeHtml o = html("A (http://go.here/) B");
     final SafeHtml n = o.linkify();
@@ -38,6 +44,7 @@
     assertEquals("A (<a href=\"http://go.here/\" target=\"_blank\">http://go.here/</a>) B", n.asString());
   }
 
+  @Test
   public void testLinkify_Parens() {
     final SafeHtml o = html("A http://go.here/#m() B");
     final SafeHtml n = o.linkify();
@@ -45,6 +52,7 @@
     assertEquals("A <a href=\"http://go.here/#m()\" target=\"_blank\">http://go.here/#m()</a> B", n.asString());
   }
 
+  @Test
   public void testLinkify_AngleBrackets1() {
     final SafeHtml o = html("A <http://go.here/> B");
     final SafeHtml n = o.linkify();
diff --git a/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_ReplaceTest.java b/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_ReplaceTest.java
index d7a3aaf..71b55a1 100644
--- a/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_ReplaceTest.java
+++ b/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_ReplaceTest.java
@@ -14,19 +14,25 @@
 
 package com.google.gwtexpui.safehtml.client;
 
-import junit.framework.TestCase;
+import org.junit.Test;
 
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
-public class SafeHtml_ReplaceTest extends TestCase {
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+
+public class SafeHtml_ReplaceTest {
+  @Test
   public void testReplaceEmpty() {
     SafeHtml o = html("A\nissue42\nB");
     assertSame(o, o.replaceAll(null));
     assertSame(o, o.replaceAll(Collections.<FindReplace> emptyList()));
   }
 
+  @Test
   public void testReplaceOneLink() {
     SafeHtml o = html("A\nissue 42\nB");
     SafeHtml n = o.replaceAll(repls(
@@ -35,6 +41,7 @@
     assertEquals("A\n<a href=\"?42\">issue 42</a>\nB", n.asString());
   }
 
+  @Test
   public void testReplaceNoLeadingOrTrailingText() {
     SafeHtml o = html("issue 42");
     SafeHtml n = o.replaceAll(repls(
@@ -43,6 +50,7 @@
     assertEquals("<a href=\"?42\">issue 42</a>", n.asString());
   }
 
+  @Test
   public void testReplaceTwoLinks() {
     SafeHtml o = html("A\nissue 42\nissue 9918\nB");
     SafeHtml n = o.replaceAll(repls(
@@ -55,6 +63,7 @@
     , n.asString());
   }
 
+  @Test
   public void testReplaceInOrder() {
     SafeHtml o = html("A\nissue 42\nReally GWTEXPUI-9918 is better\nB");
     SafeHtml n = o.replaceAll(repls(
@@ -70,6 +79,7 @@
     , n.asString());
   }
 
+  @Test
   public void testReplaceOverlappingAfterFirstChar() {
     SafeHtml o = html("abcd");
     RawFindReplace ab = new RawFindReplace("ab", "AB");
@@ -81,6 +91,7 @@
     assertEquals("ABYZ", o.replaceAll(repls(ab, bc, cd)).asString());
   }
 
+  @Test
   public void testReplaceOverlappingAtFirstCharLongestMatch() {
     SafeHtml o = html("abcd");
     RawFindReplace ab = new RawFindReplace("ab", "AB");
@@ -90,6 +101,7 @@
     assertEquals("234d", o.replaceAll(repls(abc, ab)).asString());
   }
 
+  @Test
   public void testReplaceOverlappingAtFirstCharFirstMatch() {
     SafeHtml o = html("abcd");
     RawFindReplace ab1 = new RawFindReplace("ab", "AB");
@@ -99,6 +111,7 @@
     assertEquals("12cd", o.replaceAll(repls(ab2, ab1)).asString());
   }
 
+  @Test
   public void testFailedSanitization() {
     SafeHtml o = html("abcd");
     LinkFindReplace evil = new LinkFindReplace("(b)", "javascript:alert('$1')");
diff --git a/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_WikifyListTest.java b/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_WikifyListTest.java
index 250a1b5..045555a 100644
--- a/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_WikifyListTest.java
+++ b/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_WikifyListTest.java
@@ -14,9 +14,12 @@
 
 package com.google.gwtexpui.safehtml.client;
 
-import junit.framework.TestCase;
+import org.junit.Test;
 
-public class SafeHtml_WikifyListTest extends TestCase {
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+
+public class SafeHtml_WikifyListTest {
   private static final String BEGIN_LIST = "<ul class=\"wikiList\">";
   private static final String END_LIST = "</ul>";
 
@@ -24,6 +27,7 @@
     return "<li>" + raw + "</li>";
   }
 
+  @Test
   public void testBulletList1() {
     final SafeHtml o = html("A\n\n* line 1\n* 2nd line");
     final SafeHtml n = o.wikify();
@@ -36,6 +40,7 @@
     , n.asString());
   }
 
+  @Test
   public void testBulletList2() {
     final SafeHtml o = html("A\n\n* line 1\n* 2nd line\n\nB");
     final SafeHtml n = o.wikify();
@@ -49,6 +54,7 @@
     , n.asString());
   }
 
+  @Test
   public void testBulletList3() {
     final SafeHtml o = html("* line 1\n* 2nd line\n\nB");
     final SafeHtml n = o.wikify();
@@ -61,6 +67,7 @@
     , n.asString());
   }
 
+  @Test
   public void testBulletList4() {
     final SafeHtml o = html("To see this bug, you have to:\n" //
         + "* Be on IMAP or EAS (not on POP)\n"//
@@ -75,6 +82,7 @@
     , n.asString());
   }
 
+  @Test
   public void testBulletList5() {
     final SafeHtml o = html("To see this bug,\n" //
         + "you have to:\n" //
@@ -90,6 +98,7 @@
     , n.asString());
   }
 
+  @Test
   public void testDashList1() {
     final SafeHtml o = html("A\n\n- line 1\n- 2nd line");
     final SafeHtml n = o.wikify();
@@ -102,6 +111,7 @@
     , n.asString());
   }
 
+  @Test
   public void testDashList2() {
     final SafeHtml o = html("A\n\n- line 1\n- 2nd line\n\nB");
     final SafeHtml n = o.wikify();
@@ -115,6 +125,7 @@
     , n.asString());
   }
 
+  @Test
   public void testDashList3() {
     final SafeHtml o = html("- line 1\n- 2nd line\n\nB");
     final SafeHtml n = o.wikify();
diff --git a/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_WikifyPreformatTest.java b/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_WikifyPreformatTest.java
index cbb315b..605185e 100644
--- a/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_WikifyPreformatTest.java
+++ b/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_WikifyPreformatTest.java
@@ -14,9 +14,12 @@
 
 package com.google.gwtexpui.safehtml.client;
 
-import junit.framework.TestCase;
+import org.junit.Test;
 
-public class SafeHtml_WikifyPreformatTest extends TestCase {
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+
+public class SafeHtml_WikifyPreformatTest {
   private static final String B = "<span class=\"wikiPreFormat\">";
   private static final String E = "</span><br />";
 
@@ -24,6 +27,7 @@
     return B + raw + E;
   }
 
+  @Test
   public void testPreformat1() {
     final SafeHtml o = html("A\n\n  This is pre\n  formatted");
     final SafeHtml n = o.wikify();
@@ -36,6 +40,7 @@
     , n.asString());
   }
 
+  @Test
   public void testPreformat2() {
     final SafeHtml o = html("A\n\n  This is pre\n  formatted\n\nbut this is not");
     final SafeHtml n = o.wikify();
@@ -49,6 +54,7 @@
     , n.asString());
   }
 
+  @Test
   public void testPreformat3() {
     final SafeHtml o = html("A\n\n  Q\n    <R>\n  S\n\nB");
     final SafeHtml n = o.wikify();
@@ -63,6 +69,7 @@
     , n.asString());
   }
 
+  @Test
   public void testPreformat4() {
     final SafeHtml o = html("  Q\n    <R>\n  S\n\nB");
     final SafeHtml n = o.wikify();
diff --git a/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_WikifyTest.java b/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_WikifyTest.java
index c9837037..00b29de 100644
--- a/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_WikifyTest.java
+++ b/gerrit-gwtexpui/src/test/java/com/google/gwtexpui/safehtml/client/SafeHtml_WikifyTest.java
@@ -14,9 +14,13 @@
 
 package com.google.gwtexpui.safehtml.client;
 
-import junit.framework.TestCase;
+import org.junit.Test;
 
-public class SafeHtml_WikifyTest extends TestCase {
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+
+public class SafeHtml_WikifyTest {
+  @Test
   public void testWikify_OneLine1() {
     final SafeHtml o = html("A  B");
     final SafeHtml n = o.wikify();
@@ -24,6 +28,7 @@
     assertEquals("<p>A  B</p>", n.asString());
   }
 
+  @Test
   public void testWikify_OneLine2() {
     final SafeHtml o = html("A  B\n");
     final SafeHtml n = o.wikify();
@@ -31,6 +36,7 @@
     assertEquals("<p>A  B\n</p>", n.asString());
   }
 
+  @Test
   public void testWikify_OneParagraph1() {
     final SafeHtml o = html("A\nB");
     final SafeHtml n = o.wikify();
@@ -38,6 +44,7 @@
     assertEquals("<p>A\nB</p>", n.asString());
   }
 
+  @Test
   public void testWikify_OneParagraph2() {
     final SafeHtml o = html("A\nB\n");
     final SafeHtml n = o.wikify();
@@ -45,6 +52,7 @@
     assertEquals("<p>A\nB\n</p>", n.asString());
   }
 
+  @Test
   public void testWikify_TwoParagraphs() {
     final SafeHtml o = html("A\nB\n\nC\nD");
     final SafeHtml n = o.wikify();
@@ -52,6 +60,7 @@
     assertEquals("<p>A\nB</p><p>C\nD</p>", n.asString());
   }
 
+  @Test
   public void testLinkify_SimpleHttp1() {
     final SafeHtml o = html("A http://go.here/ B");
     final SafeHtml n = o.wikify();
@@ -59,6 +68,7 @@
     assertEquals("<p>A <a href=\"http://go.here/\" target=\"_blank\">http://go.here/</a> B</p>", n.asString());
   }
 
+  @Test
   public void testLinkify_SimpleHttps2() {
     final SafeHtml o = html("A https://go.here/ B");
     final SafeHtml n = o.wikify();
@@ -66,6 +76,7 @@
     assertEquals("<p>A <a href=\"https://go.here/\" target=\"_blank\">https://go.here/</a> B</p>", n.asString());
   }
 
+  @Test
   public void testLinkify_Parens1() {
     final SafeHtml o = html("A (http://go.here/) B");
     final SafeHtml n = o.wikify();
@@ -73,6 +84,7 @@
     assertEquals("<p>A (<a href=\"http://go.here/\" target=\"_blank\">http://go.here/</a>) B</p>", n.asString());
   }
 
+  @Test
   public void testLinkify_Parens() {
     final SafeHtml o = html("A http://go.here/#m() B");
     final SafeHtml n = o.wikify();
@@ -80,6 +92,7 @@
     assertEquals("<p>A <a href=\"http://go.here/#m()\" target=\"_blank\">http://go.here/#m()</a> B</p>", n.asString());
   }
 
+  @Test
   public void testLinkify_AngleBrackets1() {
     final SafeHtml o = html("A <http://go.here/> B");
     final SafeHtml n = o.wikify();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
index 40e5252..7b5389e 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
@@ -71,6 +71,7 @@
 import com.google.gerrit.client.dashboards.DashboardInfo;
 import com.google.gerrit.client.dashboards.DashboardList;
 import com.google.gerrit.client.diff.SideBySide2;
+import com.google.gerrit.client.documentation.DocScreen;
 import com.google.gerrit.client.groups.GroupApi;
 import com.google.gerrit.client.groups.GroupInfo;
 import com.google.gerrit.client.patches.PatchScreen;
@@ -201,6 +202,9 @@
     if (matchPrefix("/q/", token)) {
       query(token);
 
+    } else if (matchPrefix("/Documentation/", token)) {
+      docSearch(token);
+
     } else if (matchPrefix("/c/", token)) {
       change(token);
 
@@ -884,4 +888,12 @@
       }
     }
   }
+
+  private static void docSearch(final String token) {
+    GWT.runAsync(new AsyncSplit(token) {
+      public void onSuccess() {
+        Gerrit.display(token, new DocScreen(skip(token)));
+      }
+    });
+  }
 }
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 e73670f..568a15c 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
@@ -978,6 +978,9 @@
   private static void addExtensionLink(final LinkMenuBar m, final TopMenuItem item) {
     final Anchor atag = anchor(item.getName(), item.getUrl());
     atag.setTarget(item.getTarget());
+    if (item.getId() != null) {
+      atag.getElement().setAttribute("id", item.getId());
+    }
     m.add(atag);
   }
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritMessages.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritMessages.java
index cbb5513..21da8ce 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritMessages.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritMessages.java
@@ -34,4 +34,6 @@
 
   String pluginFailed(String scriptPath);
   String cannotDownloadPlugin(String scriptPath);
+
+  String parentUpdateFailed(String message);
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritMessages.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritMessages.properties
index 5ab8b3b..8196e98 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritMessages.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritMessages.properties
@@ -15,3 +15,5 @@
 
 pluginFailed = Plugin JavaScript {0} failed to load
 cannotDownloadPlugin = Cannot download JavaScript plugin from: {0}.
+
+parentUpdateFailed = Setting parent project failed: {0}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritResources.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritResources.java
index 80d65b0..dffa7c4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritResources.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritResources.java
@@ -57,4 +57,7 @@
 
   @Source("draftComments.png")
   public ImageResource draftComments();
+
+  @Source("readOnly.png")
+  public ImageResource readOnly();
 }
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 aae506d..4c69300 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
@@ -80,6 +80,7 @@
 
     suggestions.add("commit:");
     suggestions.add("comment:");
+    suggestions.add("conflicts:");
     suggestions.add("project:");
     suggestions.add("parentproject:");
     suggestions.add("branch:");
@@ -90,7 +91,6 @@
     suggestions.add("label:");
     suggestions.add("message:");
     suggestions.add("file:");
-
     suggestions.add("has:");
     suggestions.add("has:draft");
     suggestions.add("has:star");
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 333dcfa..0aeeac6 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
@@ -77,14 +77,14 @@
       Confirm the default path <em>.ssh/id_rsa</em>\
     </li>\
     <li>\
-      Enter a passphrase (recommended) or leave it blank.<br>\
-      Remember this passphrase, as you will need it to unlock the<br>\
+      Enter a passphrase (recommended) or leave it blank.<br />\
+      Remember this passphrase, as you will need it to unlock the<br />\
       key whenever you use it.\
     </li>\
     <li>\
-      Open <em>~/.ssh/id_rsa.pub</em> and copy & paste the contents into<br>\
-      the box below, then click on "Add".<br>\
-      Note that <em>id_rsa.pub</em> is your public key and can be shared,<br>\
+      Open <em>~/.ssh/id_rsa.pub</em> and copy & paste the contents into<br />\
+      the box below, then click on "Add".<br />\
+      Note that <em>id_rsa.pub</em> is your public key and can be shared,<br />\
       while <em>id_rsa</em> is your private key and should be kept secret.\
     </li>\
   <\ol>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyPreferencesScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyPreferencesScreen.java
index 731eaeb..2dd4df7 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyPreferencesScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyPreferencesScreen.java
@@ -280,7 +280,7 @@
         return;
       }
     }
-    if (currentValue != defaultValue) {
+    if (!currentValue.equals(defaultValue)) {
       setListBox(f, defaultValue, defaultValue);
     }
   }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessEditor.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessEditor.java
index 49a9aa4..567f14c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessEditor.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessEditor.java
@@ -18,6 +18,7 @@
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.GitwebLink;
 import com.google.gerrit.client.ui.Hyperlink;
+import com.google.gerrit.client.ui.ParentProjectBox;
 import com.google.gerrit.common.data.AccessSection;
 import com.google.gerrit.common.data.ProjectAccess;
 import com.google.gerrit.reviewdb.client.Branch;
@@ -56,6 +57,10 @@
   Hyperlink parentProject;
 
   @UiField
+  @Editor.Ignore
+  ParentProjectBox parentProjectBox;
+
+  @UiField
   DivElement history;
 
   @UiField
@@ -106,6 +111,11 @@
       parentProject.setText(parent.get());
       parentProject.setTargetHistoryToken( //
           Dispatcher.toProjectAdmin(parent, ProjectScreen.ACCESS));
+
+      parentProjectBox.setVisible(editing && value.canChangeParent());
+      parentProjectBox.setProject(value.getProjectName());
+      parentProjectBox.setParentProject(value.getInheritsFrom());
+      parentProject.setVisible(!parentProjectBox.isVisible());
     } else {
       inheritsFrom.getStyle().setDisplay(Display.NONE);
     }
@@ -135,6 +145,7 @@
       }
     }
     value.setLocal(keep);
+    value.setInheritsFrom(parentProjectBox.getParentProjectName());
   }
 
   @Override
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessEditor.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessEditor.ui.xml
index 4942b83..120824b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessEditor.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessEditor.ui.xml
@@ -56,6 +56,9 @@
   <div ui:field='inheritsFrom' class='{style.inheritsFrom}'>
     <span class='{style.parentTitle}'><ui:msg>Rights Inherit From:</ui:msg></span>
     <q:Hyperlink ui:field='parentProject' styleName='{style.parentLink}'/>
+    <q:ParentProjectBox
+      ui:field='parentProjectBox'
+      visible='false'/>
   </div>
   <div ui:field='history' class='{style.history}'>
     <span class='{style.historyTitle}'><ui:msg>History:</ui:msg></span>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessScreen.java
index ef7f560..c76bba9 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessScreen.java
@@ -17,6 +17,7 @@
 import static com.google.gerrit.common.ProjectAccessUtil.mergeSections;
 import static com.google.gerrit.common.ProjectAccessUtil.removeEmptyPermissionsAndSections;
 
+import com.google.gerrit.client.ErrorDialog;
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.config.CapabilityInfo;
 import com.google.gerrit.client.config.ConfigServerApi;
@@ -28,6 +29,7 @@
 import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.common.data.AccessSection;
 import com.google.gerrit.common.data.ProjectAccess;
+import com.google.gerrit.common.errors.UpdateParentFailedException;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gwt.core.client.GWT;
@@ -45,6 +47,7 @@
 import com.google.gwt.user.client.ui.UIObject;
 import com.google.gwt.user.client.ui.VerticalPanel;
 import com.google.gwtexpui.globalkey.client.NpTextArea;
+import com.google.gwtjsonrpc.client.RemoteJsonException;
 
 import java.util.Collections;
 import java.util.HashMap;
@@ -205,6 +208,7 @@
         access.getRevision(), //
         message, //
         access.getLocal(), //
+        access.getInheritsFrom(), //
         new GerritCallback<ProjectAccess>() {
           @Override
           public void onSuccess(ProjectAccess newAccess) {
@@ -250,7 +254,15 @@
           public void onFailure(Throwable caught) {
             error.clear();
             enable(true);
-            super.onFailure(caught);
+            if (caught instanceof RemoteJsonException
+                && caught.getMessage().startsWith(
+                    UpdateParentFailedException.MESSAGE)) {
+              new ErrorDialog(Gerrit.M.parentUpdateFailed(caught.getMessage()
+                  .substring(UpdateParentFailedException.MESSAGE.length() + 1)))
+                  .center();
+            } else {
+              super.onFailure(caught);
+            }
           }
         });
   }
@@ -275,6 +287,7 @@
         access.getRevision(), //
         message, //
         access.getLocal(), //
+        access.getInheritsFrom(), //
         new GerritCallback<Change.Id>() {
           @Override
           public void onSuccess(Change.Id changeId) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectListScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectListScreen.java
index da88034..23e13d4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectListScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectListScreen.java
@@ -37,6 +37,7 @@
 import com.google.gwt.user.client.ui.Anchor;
 import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.Image;
 import com.google.gwt.user.client.ui.Label;
 import com.google.gwtexpui.globalkey.client.NpTextBox;
 
@@ -131,6 +132,23 @@
 
       @Override
       protected void populate(final int row, final ProjectInfo k) {
+        Image state = new Image();
+        switch (k.state()) {
+          case HIDDEN:
+            state.setResource(Gerrit.RESOURCES.redNot());
+            state.setTitle(Util.toLongString(k.state()));
+            table.setWidget(row, ProjectsTable.C_STATE, state);
+            break;
+          case READ_ONLY:
+            state.setResource(Gerrit.RESOURCES.readOnly());
+            state.setTitle(Util.toLongString(k.state()));
+            table.setWidget(row, ProjectsTable.C_STATE, state);
+            break;
+          default:
+            // Intentionally left blank, do not show an icon when active.
+            break;
+        }
+
         FlowPanel fp = new FlowPanel();
         fp.add(new ProjectSearchLink(k.name_key()));
         fp.add(new HighlightingInlineHyperlink(k.name(), link(k), subname));
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/deleteHover.png b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/deleteHover.png
index 839e8ef..9fde3fa 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/deleteHover.png
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/deleteHover.png
Binary files differ
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/deleteNormal.png b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/deleteNormal.png
index ffddb6f..47a1195 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/deleteNormal.png
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/deleteNormal.png
Binary files differ
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/editText.png b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/editText.png
index 188e1c1..2927275 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/editText.png
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/editText.png
Binary files differ
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/undoNormal.png b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/undoNormal.png
index 8b0fef9..b780f75 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/undoNormal.png
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/undoNormal.png
Binary files differ
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 60377c4..7b00821 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
@@ -135,10 +135,30 @@
   }
 
   static final void post(RestApi api, JavaScriptObject in, JavaScriptObject cb) {
+    if (NativeString.is(in)) {
+      post(api, ((NativeString) in).asString(), cb);
+    } else {
+      api.post(in, wrap(cb));
+    }
+  }
+
+  static final void post(RestApi api, String in, JavaScriptObject cb) {
     api.post(in, wrap(cb));
   }
 
+  static final void put(RestApi api, JavaScriptObject cb) {
+    api.put(wrap(cb));
+  }
+
   static final void put(RestApi api, JavaScriptObject in, JavaScriptObject cb) {
+    if (NativeString.is(in)) {
+      put(api, ((NativeString) in).asString(), cb);
+    } else {
+      api.put(in, wrap(cb));
+    }
+  }
+
+  static final void put(RestApi api, String in, JavaScriptObject cb) {
     api.put(in, wrap(cb));
   }
 
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 f3fb1fa..1e2e19e 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
@@ -59,9 +59,24 @@
 
       _api: function(u) {return @com.google.gerrit.client.rpc.RestApi::new(Ljava/lang/String;)(u)},
       get: function(u,b){@com.google.gerrit.client.api.ActionContext::get(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),b)},
-      post: function(u,i,b){@com.google.gerrit.client.api.ActionContext::post(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),i,b)},
-      put: function(u,i,b){@com.google.gerrit.client.api.ActionContext::put(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),i,b)},
+      post: function(u,i,b){
+        if (typeof i=='string')
+          @com.google.gerrit.client.api.ActionContext::post(Lcom/google/gerrit/client/rpc/RestApi;Ljava/lang/String;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),i,b);
+        else
+          @com.google.gerrit.client.api.ActionContext::post(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),i,b);
+      },
+      put: function(u,i,b){
+        if(b){
+          if(typeof i=='string')
+            @com.google.gerrit.client.api.ActionContext::put(Lcom/google/gerrit/client/rpc/RestApi;Ljava/lang/String;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),i,b);
+          else
+            @com.google.gerrit.client.api.ActionContext::put(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),i,b);
+        }else{
+          @com.google.gerrit.client.api.ActionContext::put(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),i)
+        }
+      },
       'delete': function(u,b){@com.google.gerrit.client.api.ActionContext::delete(Lcom/google/gerrit/client/rpc/RestApi;Lcom/google/gwt/core/client/JavaScriptObject;)(this._api(u),b)},
+      JsonString: @com.google.gerrit.client.rpc.NativeString::TYPE,
     };
 
     Plugin.prototype = {
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 523a0a6..ce8a062 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
@@ -174,6 +174,7 @@
       color: #444;
       vertical-align: top;
       text-align: left;
+      padding-top: 3px;
       padding-right: 5px;
       white-space: nowrap;
     }
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 cd1f304..939f946 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
@@ -82,7 +82,7 @@
           public void onSuccess(JavaScriptObject msg) {
             Gerrit.display(PageLinks.toChange(changeId));
             hide();
-          };
+          }
         });
   }
 
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 c8eb13a..75ca6b3 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
@@ -56,6 +56,8 @@
 import java.util.TreeSet;
 
 class ReplyBox extends Composite {
+  private static final String CODE_REVIEW = "Code-Review";
+
   interface Binder extends UiBinder<HTMLPanel, ReplyBox> {}
   private static final Binder uiBinder = GWT.create(Binder.class);
 
@@ -67,7 +69,7 @@
   private final PatchSet.Id psId;
   private final String revision;
   private ReviewInput in = ReviewInput.create();
-  private List<Runnable> lgtm;
+  private Runnable lgtm;
 
   @UiField Styles style;
   @UiField NpTextArea message;
@@ -91,7 +93,6 @@
       UIObject.setVisible(labelsParent, false);
     } else {
       Collections.sort(names);
-      lgtm = new ArrayList<Runnable>(names.size());
       renderLabels(names, all, permitted);
     }
   }
@@ -118,11 +119,7 @@
       Scheduler.get().scheduleDeferred(new ScheduledCommand() {
         @Override
         public void execute() {
-          if (message.getValue().startsWith("LGTM")) {
-            for (Runnable r : lgtm) {
-              r.run();
-            }
-          }
+          lgtm.run();
         }
       });
     }
@@ -236,8 +233,8 @@
       }
     }
 
-    if (!group.isEmpty()) {
-      lgtm.add(new Runnable() {
+    if (CODE_REVIEW.equalsIgnoreCase(id) && !group.isEmpty()) {
+      lgtm = new Runnable() {
         @Override
         public void run() {
           for (int i = 0; i < group.size() - 1; i++) {
@@ -245,7 +242,7 @@
           }
           group.get(group.size() - 1).setValue(true, true);
         }
-      });
+      };
     }
   }
 
@@ -269,12 +266,14 @@
     b.setStyleName(style.label_name());
     labelsTable.setWidget(row, 0, b);
 
-    lgtm.add(new Runnable() {
-      @Override
-      public void run() {
-        b.setValue(true, true);
-      }
-    });
+    if (CODE_REVIEW.equalsIgnoreCase(id)) {
+      lgtm = new Runnable() {
+        @Override
+        public void run() {
+          b.setValue(true, true);
+        }
+      };
+    }
   }
 
   private static boolean isCheckBox(Set<Short> values) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/remove_reviewer.png b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/remove_reviewer.png
index 9e494dd..5a3e6f0 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/remove_reviewer.png
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/remove_reviewer.png
Binary files differ
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/star_filled.png b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/star_filled.png
index 39bddb1..db1e24e 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/star_filled.png
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/star_filled.png
Binary files differ
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeApi.java
index 97b0166..03058fe 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeApi.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeApi.java
@@ -171,7 +171,7 @@
 
     protected CherryPickInput() {
     }
-  };
+  }
 
   private static class SubmitInput extends JavaScriptObject {
     final native void wait_for_merge(boolean b) /*-{ this.wait_for_merge=b; }-*/;
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 42705db..48aa02d 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
@@ -453,7 +453,7 @@
           for (Patch p : detail.getPatches()) {
             openWindow(Dispatcher.toPatchUnified(base, p.getKey()));
           }
-        };
+        }
       });
       table.setWidget(row, C_UNIFIED, unified);
     }
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 fa3d784..d29fb0f 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
@@ -18,7 +18,7 @@
 
 public class ReviewInput extends JavaScriptObject {
   public static enum NotifyHandling {
-    NONE, OWNER, OWNER_REVIEWERS, ALL;
+    NONE, OWNER, OWNER_REVIEWERS, ALL
   }
 
   public static ReviewInput create() {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/StarredChanges.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/StarredChanges.java
index 7d2084a..b097bd8 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/StarredChanges.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/StarredChanges.java
@@ -15,19 +15,23 @@
 package com.google.gerrit.client.changes;
 
 import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.client.rpc.GerritCallback;
-import com.google.gerrit.common.data.ToggleStarRequest;
+import com.google.gerrit.client.account.AccountApi;
+import com.google.gerrit.client.rpc.RestApi;
 import com.google.gerrit.reviewdb.client.Change;
+import com.google.gwt.core.client.JavaScriptObject;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.dom.client.KeyPressEvent;
 import com.google.gwt.resources.client.ImageResource;
+import com.google.gwt.user.client.rpc.AsyncCallback;
 import com.google.gwt.user.client.ui.Image;
 import com.google.gwtexpui.globalkey.client.KeyCommand;
-import com.google.gwtjsonrpc.common.VoidResult;
 import com.google.web.bindery.event.shared.Event;
 import com.google.web.bindery.event.shared.HandlerRegistration;
 
+import java.util.LinkedHashMap;
+import java.util.Map;
+
 /** Supports the star icon displayed on changes and tracking the status. */
 public class StarredChanges {
   private static final Event.Type<ChangeStarHandler> TYPE =
@@ -105,57 +109,52 @@
   public static void toggleStar(
       final Change.Id changeId,
       final boolean newValue) {
-    if (next == null) {
-      next = new ToggleStarRequest();
-    }
-    next.toggle(changeId, newValue);
+    pending.put(changeId, newValue);
     fireChangeStarEvent(changeId, newValue);
     if (!busy) {
-      start();
+      startRequest();
     }
   }
 
-  private static ToggleStarRequest next;
   private static boolean busy;
+  private static final Map<Change.Id, Boolean> pending =
+      new LinkedHashMap<Change.Id, Boolean>(4);
 
-  private static void start() {
-    final ToggleStarRequest req = next;
-    next = null;
+  private static void startRequest() {
     busy = true;
 
-    Util.LIST_SVC.toggleStars(req, new GerritCallback<VoidResult>() {
+    final Change.Id id = pending.keySet().iterator().next();
+    final boolean starred = pending.remove(id);
+    RestApi call = AccountApi.self().view("starred.changes").id(id.get());
+    AsyncCallback<JavaScriptObject> cb = new AsyncCallback<JavaScriptObject>() {
       @Override
-      public void onSuccess(VoidResult result) {
-        if (next != null) {
-          start();
-        } else {
+      public void onSuccess(JavaScriptObject none) {
+        if (pending.isEmpty()) {
           busy = false;
+        } else {
+          startRequest();
         }
       }
 
       @Override
       public void onFailure(Throwable caught) {
-        rollback(req);
-        if (next != null) {
-          rollback(next);
-          next = null;
+        if (!starred && RestApi.isStatus(caught, 404)) {
+          onSuccess(null);
+          return;
         }
-        busy = false;
-        super.onFailure(caught);
-      }
-    });
-  }
 
-  private static void rollback(ToggleStarRequest req) {
-    if (req.getAddSet() != null) {
-      for (Change.Id id : req.getAddSet()) {
-        fireChangeStarEvent(id, false);
+        fireChangeStarEvent(id, !starred);
+        for (Map.Entry<Change.Id, Boolean> e : pending.entrySet()) {
+          fireChangeStarEvent(e.getKey(), !e.getValue());
+        }
+        pending.clear();
+        busy = false;
       }
-    }
-    if (req.getRemoveSet() != null) {
-      for (Change.Id id : req.getRemoveSet()) {
-        fireChangeStarEvent(id, true);
-      }
+    };
+    if (starred) {
+      call.put(cb);
+    } else {
+      call.delete(cb);
     }
   }
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/Util.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/Util.java
index 590ad87..76dfd58 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/Util.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/Util.java
@@ -15,7 +15,6 @@
 package com.google.gerrit.client.changes;
 
 import com.google.gerrit.common.data.ChangeDetailService;
-import com.google.gerrit.common.data.ChangeListService;
 import com.google.gerrit.common.data.ChangeManageService;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gwt.core.client.GWT;
@@ -27,7 +26,6 @@
   public static final ChangeResources R = GWT.create(ChangeResources.class);
 
   public static final ChangeDetailService DETAIL_SVC;
-  public static final ChangeListService LIST_SVC;
   public static final ChangeManageService MANAGE_SVC;
 
   private static final int SUBJECT_MAX_LENGTH = 80;
@@ -38,9 +36,6 @@
     DETAIL_SVC = GWT.create(ChangeDetailService.class);
     JsonUtil.bind(DETAIL_SVC, "rpc/ChangeDetailService");
 
-    LIST_SVC = GWT.create(ChangeListService.class);
-    JsonUtil.bind(LIST_SVC, "rpc/ChangeListService");
-
     MANAGE_SVC = GWT.create(ChangeManageService.class);
     JsonUtil.bind(MANAGE_SVC, "rpc/ChangeManageService");
   }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/removeReviewerNormal.png b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/removeReviewerNormal.png
index 839e8ef..9fde3fa 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/removeReviewerNormal.png
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/removeReviewerNormal.png
Binary files differ
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/removeReviewerPressed.png b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/removeReviewerPressed.png
index 2e509ec..e46f0aa 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/removeReviewerPressed.png
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/removeReviewerPressed.png
Binary files differ
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffApi.java
index 826d477..aee30df 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffApi.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffApi.java
@@ -23,8 +23,8 @@
 
 public class DiffApi {
   public enum IgnoreWhitespace {
-    NONE, TRAILING, CHANGED, ALL;
-  };
+    NONE, TRAILING, CHANGED, ALL
+  }
 
   public static void list(int id, String revision,
       AsyncCallback<NativeMap<FileInfo>> cb) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffInfo.java
index f833509..d5f7819 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffInfo.java
@@ -93,7 +93,7 @@
   }
 
   public enum IntraLineStatus {
-    OFF, OK, TIMEOUT, FAILURE;
+    OFF, OK, TIMEOUT, FAILURE
   }
 
   public static class FileMeta extends JavaScriptObject {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DisplaySide.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DisplaySide.java
index c51a673..36911bd 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DisplaySide.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DisplaySide.java
@@ -16,5 +16,5 @@
 
 /** Enum representing the side on a side-by-side view */
 enum DisplaySide {
-  A, B;
+  A, B
 }
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 0a01adc..e0c0cd4 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
@@ -69,7 +69,6 @@
 import com.google.gwtexpui.globalkey.client.ShowHelpCommand;
 
 import net.codemirror.lib.CodeMirror;
-import net.codemirror.lib.CodeMirror.EventHandler;
 import net.codemirror.lib.CodeMirror.GutterClickHandler;
 import net.codemirror.lib.CodeMirror.LineClassWhere;
 import net.codemirror.lib.CodeMirror.LineHandle;
@@ -111,7 +110,6 @@
 
   private CodeMirror cmA;
   private CodeMirror cmB;
-  private CodeMirror lastFocused;
   private ScrollSynchronizer scrollingGlue;
   private HandlerRegistration resizeHandler;
   private JsArray<CommentInfo> publishedBase;
@@ -279,17 +277,9 @@
     cm.on("focus", new Runnable() {
       @Override
       public void run() {
-        lastFocused = cm;
         updateActiveLine(cm).run();
       }
     });
-    cm.on("contextmenu", new EventHandler() {
-      @Override
-      public void handle(CodeMirror instance, NativeEvent event) {
-        CodeMirror.setObjectProperty(event, "codemirrorIgnore", true);
-        lastFocused.focus();
-      }
-    });
     cm.addKeyMap(KeyMap.create()
         .on("'a'", upToChange(true))
         .on("'u'", upToChange(false))
@@ -316,12 +306,30 @@
             (header.hasNext() ? header.next : header.up).go();
           }
         })
-        .on("Shift-Alt-/", new Runnable() {
+        .on("Shift-/", new Runnable() {
           @Override
           public void run() {
             new ShowHelpCommand().onKeyPress(null);
           }
         })
+        .on("Ctrl-F", new Runnable() {
+          @Override
+          public void run() {
+            CodeMirror.handleVimKey(cm, "/");
+          }
+        })
+        .on("Space", new Runnable() {
+          @Override
+          public void run() {
+            CodeMirror.handleVimKey(cm, "<PageDown>");
+          }
+        })
+        .on("Ctrl-A", new Runnable() {
+          @Override
+          public void run() {
+            cm.execCommand("selectAll");
+          }
+        })
         .on("N", maybeNextVimSearch(cm))
         .on("P", diffChunkNav(cm, true))
         .on("Shift-O", openClosePublished(cm))
@@ -336,9 +344,13 @@
     keysNavigation.add(new UpToChangeCommand2(revision, 0, 'u'));
     keysNavigation.add(new NoOpKeyCommand(0, 'j', PatchUtil.C.lineNext()));
     keysNavigation.add(new NoOpKeyCommand(0, 'k', PatchUtil.C.linePrev()));
+    keysNavigation.add(new NoOpKeyCommand(0, 'n', PatchUtil.C.chunkNext2()));
+    keysNavigation.add(new NoOpKeyCommand(0, 'p', PatchUtil.C.chunkPrev2()));
 
     keysAction = new KeyCommandSet(Gerrit.C.sectionActions());
     keysAction.add(new NoOpKeyCommand(0, 'o', PatchUtil.C.expandComment()));
+    keysAction.add(new NoOpKeyCommand(
+        KeyCommand.M_SHIFT, 'o', PatchUtil.C.expandAllCommentsOnCurrentLine()));
     keysAction.add(new KeyCommand(0, 'r', PatchUtil.C.toggleReviewed()) {
       @Override
       public void onKeyPress(KeyPressEvent event) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SidePanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SidePanel.java
index fb1a96f..b0431e9 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SidePanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SidePanel.java
@@ -49,7 +49,7 @@
   }
 
   enum GutterType {
-    COMMENT, DRAFT, INSERT, DELETE, EDIT;
+    COMMENT, DRAFT, INSERT, DELETE, EDIT
   }
 
   @UiField
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/DocConstants.java
similarity index 63%
copy from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
copy to gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/DocConstants.java
index a5371d2..f6b7a9d 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/DocConstants.java
@@ -12,19 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.acceptance.rest.change;
+package com.google.gerrit.client.documentation;
 
-import com.google.common.collect.Maps;
+import com.google.gwt.i18n.client.Constants;
 
-import java.util.Map;
+public interface DocConstants extends Constants {
+  String keyReloadSearch();
 
-public class ReviewInput {
-  Map<String, Integer> labels;
-
-  public static ReviewInput approve() {
-    ReviewInput in = new ReviewInput();
-    in.labels = Maps.newHashMap();
-    in.labels.put("Code-Review", 2);
-    return in;
-  }
+  String docItemHelp();
+  String docTableColumnTitle();
+  String docTableNone();
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/DocConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/DocConstants.properties
new file mode 100644
index 0000000..b48c507
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/DocConstants.properties
@@ -0,0 +1,5 @@
+keyReloadSearch = Reload documentation list
+
+docItemHelp = documentation
+docTableColumnTitle = Title
+docTableNone = (None)
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/DocInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/DocInfo.java
new file mode 100644
index 0000000..6235186
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/DocInfo.java
@@ -0,0 +1,31 @@
+// 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.client.documentation;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.JavaScriptObject;
+
+public class DocInfo extends JavaScriptObject {
+
+  public final native String title() /*-{ return this.title; }-*/;
+  public final native String url() /*-{ return this.url; }-*/;
+
+  protected DocInfo() {
+  }
+
+  public final String getFullUrl() {
+    return GWT.getHostPageBaseURL() + url();
+  }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/DocMessages.java
similarity index 63%
copy from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
copy to gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/DocMessages.java
index a5371d2..df62b92 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/DocMessages.java
@@ -12,19 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.acceptance.rest.change;
+package com.google.gerrit.client.documentation;
 
-import com.google.common.collect.Maps;
+import com.google.gwt.i18n.client.Messages;
 
-import java.util.Map;
-
-public class ReviewInput {
-  Map<String, Integer> labels;
-
-  public static ReviewInput approve() {
-    ReviewInput in = new ReviewInput();
-    in.labels = Maps.newHashMap();
-    in.labels.put("Code-Review", 2);
-    return in;
-  }
+public interface DocMessages extends Messages {
+  String docQueryWindowTitle(String query);
+  String docQueryPageTitle(String query);
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/DocMessages.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/DocMessages.properties
new file mode 100644
index 0000000..8810a4a
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/DocMessages.properties
@@ -0,0 +1,2 @@
+docQueryWindowTitle = {0}
+docQueryPageTitle = Search for {0} in documentation
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/DocScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/DocScreen.java
new file mode 100644
index 0000000..0a87d29
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/DocScreen.java
@@ -0,0 +1,78 @@
+// 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.client.documentation;
+
+import com.google.gerrit.client.rpc.GerritCallback;
+import com.google.gerrit.client.rpc.RestApi;
+import com.google.gerrit.client.ui.Screen;
+import com.google.gwt.core.client.JsArray;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwtorm.client.KeyUtil;
+
+public class DocScreen extends Screen {
+  private static final String URI = "/Documentation/";
+
+  private DocTable table;
+  private final String query;
+
+  public DocScreen(String query) {
+    this.query = KeyUtil.decode(query);
+  }
+
+  @Override
+  protected void onInitUI() {
+    super.onInitUI();
+
+    table = new DocTable();
+    table.setSavePointerId(query);
+    add(table);
+
+    setWindowTitle(Util.M.docQueryWindowTitle(query));
+    setPageTitle(Util.M.docQueryPageTitle(query));
+  }
+
+  @Override
+  protected void onLoad() {
+    super.onLoad();
+    doQuery();
+  }
+
+  @Override
+  public void registerKeys() {
+    super.registerKeys();
+    table.setRegisterKeys(true);
+  }
+
+  private AsyncCallback<JsArray<DocInfo>> loadCallback() {
+    return new GerritCallback<JsArray<DocInfo>>() {
+      @Override
+      public void onSuccess(JsArray<DocInfo> result) {
+        displayResults(result);
+        display();
+      }
+    };
+  }
+
+  private void displayResults(JsArray<DocInfo> result) {
+    table.display(result);
+    table.finishDisplay();
+  }
+
+  private void doQuery() {
+    RestApi call = new RestApi(URI);
+    call.addParameterRaw("q", KeyUtil.encode(query));
+    call.get(loadCallback());
+  }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/DocTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/DocTable.java
new file mode 100644
index 0000000..f176372
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/DocTable.java
@@ -0,0 +1,125 @@
+// 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.client.documentation;
+
+import com.google.gerrit.client.Gerrit;
+import com.google.gerrit.client.ui.NavigationTable;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.core.client.JsArray;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.Anchor;
+import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;
+import com.google.gwt.user.client.ui.HTMLTable.Cell;
+import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
+
+class DocTable extends NavigationTable<DocInfo> {
+  private static final int C_TITLE = 1;
+
+  private int rows = 0;
+  private int dataBeginRow = 0;
+
+  public DocTable() {
+    super(Util.C.docItemHelp());
+
+    table.setText(0, C_TITLE, Util.C.docTableColumnTitle());
+
+    FlexCellFormatter fmt = table.getFlexCellFormatter();
+    fmt.addStyleName(0, C_TITLE, Gerrit.RESOURCES.css().dataHeader());
+
+    table.addClickHandler(new ClickHandler() {
+      @Override
+      public void onClick(ClickEvent event) {
+        Cell cell = table.getCellForEvent(event);
+        if (cell == null) {
+          return;
+        }
+        if (getRowItem(cell.getRowIndex()) != null) {
+          movePointerTo(cell.getRowIndex());
+        }
+      }
+    });
+  }
+
+  @Override
+  protected Object getRowItemKey(DocInfo item) {
+    return item.url();
+  }
+
+  @Override
+  protected void onOpenRow(int row) {
+    DocInfo d = getRowItem(row);
+    Window.Location.assign(d.getFullUrl());
+  }
+
+  private void insertNoneRow(int row) {
+    table.insertRow(row);
+    table.setText(row, 0, Util.C.docTableNone());
+    FlexCellFormatter fmt = table.getFlexCellFormatter();
+    fmt.setStyleName(row, 0, Gerrit.RESOURCES.css().emptySection());
+  }
+
+  private void insertDocRow(int row) {
+    table.insertRow(row);
+    applyDataRowStyle(row);
+  }
+
+  @Override
+  protected void applyDataRowStyle(int row) {
+    super.applyDataRowStyle(row);
+    CellFormatter fmt = table.getCellFormatter();
+    fmt.addStyleName(row, C_TITLE, Gerrit.RESOURCES.css().dataCell());
+    fmt.addStyleName(row, C_TITLE, Gerrit.RESOURCES.css().cSUBJECT());
+  }
+
+  private void populateDocRow(int row, DocInfo d) {
+    table.setWidget(row, C_TITLE, new DocLink(d));
+    setRowItem(row, d);
+  }
+
+  public void display(JsArray<DocInfo> docList) {
+    int sz = docList != null ? docList.length() : 0;
+    boolean hadData = rows > 0;
+
+    if (hadData) {
+      while (sz < rows) {
+        table.removeRow(dataBeginRow);
+        rows--;
+      }
+    } else {
+      table.removeRow(dataBeginRow);
+    }
+
+    if (sz == 0) {
+      insertNoneRow(dataBeginRow);
+      return;
+    }
+
+    while (rows < sz) {
+      insertDocRow(dataBeginRow + rows);
+      rows++;
+    }
+    for (int i = 0; i < sz; i++) {
+      populateDocRow(dataBeginRow + i, docList.get(i));
+    }
+  }
+
+  public static class DocLink extends Anchor {
+    public DocLink(DocInfo d) {
+      super(com.google.gerrit.client.changes.Util.cropSubject(d.title()));
+      setHref(d.getFullUrl());
+    }
+  }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/Util.java
similarity index 63%
copy from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
copy to gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/Util.java
index a5371d2..273ead8 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/documentation/Util.java
@@ -12,19 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.acceptance.rest.change;
+package com.google.gerrit.client.documentation;
 
-import com.google.common.collect.Maps;
+import com.google.gwt.core.client.GWT;
 
-import java.util.Map;
-
-public class ReviewInput {
-  Map<String, Integer> labels;
-
-  public static ReviewInput approve() {
-    ReviewInput in = new ReviewInput();
-    in.labels = Maps.newHashMap();
-    in.labels.put("Code-Review", 2);
-    return in;
-  }
+public class Util {
+  public static final DocConstants C = GWT.create(DocConstants.class);
+  public static final DocMessages M = GWT.create(DocMessages.class);
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/downloadIcon.png b/gerrit-gwtui/src/main/java/com/google/gerrit/client/downloadIcon.png
index 22ff495..1a6520e 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/downloadIcon.png
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/downloadIcon.png
Binary files differ
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/draftComments.png b/gerrit-gwtui/src/main/java/com/google/gerrit/client/draftComments.png
index 31c770f..276912a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/draftComments.png
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/draftComments.png
Binary files differ
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editText.png b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editText.png
index 188e1c1..2927275 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editText.png
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editText.png
Binary files differ
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/extensions/TopMenuItem.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/extensions/TopMenuItem.java
index 7906fd0..22bb981 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/extensions/TopMenuItem.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/extensions/TopMenuItem.java
@@ -20,6 +20,7 @@
   public final native String getName() /*-{ return this.name; }-*/;
   public final native String getUrl() /*-{ return this.url; }-*/;
   public final native String getTarget() /*-{ return this.target; }-*/;
+  public final native String getId() /*-{ return this.id; }-*/;
 
   protected TopMenuItem() {
   }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/greenCheck.png b/gerrit-gwtui/src/main/java/com/google/gerrit/client/greenCheck.png
index cd70687..207c0e7 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/greenCheck.png
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/greenCheck.png
Binary files differ
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 c6793d6..908801b 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
@@ -45,10 +45,13 @@
   String lineNext();
   String chunkPrev();
   String chunkNext();
+  String chunkPrev2();
+  String chunkNext2();
   String commentPrev();
   String commentNext();
   String fileList();
   String expandComment();
+  String expandAllCommentsOnCurrentLine();
 
   String toggleReviewed();
   String markAsReviewedAndGoToNext();
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 5259a4c..a1b6192 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
@@ -27,10 +27,13 @@
 lineNext = Next line
 chunkPrev = Previous diff chunk or comment
 chunkNext = Next diff chunk or comment
+chunkPrev2 = Previous diff chunk
+chunkNext2 = Next diff chunk or search result
 commentPrev = Previous comment
 commentNext = Next comment
 fileList = Browse files in patch set
 expandComment = Expand or collapse comment
+expandAllCommentsOnCurrentLine = Expand or collapse all comments on current line
 
 toggleReviewed = Toggle the reviewed flag
 markAsReviewedAndGoToNext = Mark patch as reviewed and go to next unreviewed patch
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchLine.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchLine.java
index 9726bbb..4863af2 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchLine.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchLine.java
@@ -16,7 +16,7 @@
 
 class PatchLine {
   static enum Type {
-    DELETE, INSERT, REPLACE, CONTEXT;
+    DELETE, INSERT, REPLACE, CONTEXT
   }
 
   private PatchLine.Type type;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.java
index 9795a64..08799a5 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.java
@@ -147,7 +147,7 @@
         }
       }
       toggleEnabledStatus(on);
-    };
+    }
   }
 
   public void setEnableSmallFileFeatures(final boolean on) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java
index 62dbf1c7..ebae86a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java
@@ -110,6 +110,15 @@
         });
   }
 
+  public static void getChildren(Project.NameKey name, boolean recursive,
+      AsyncCallback<JsArray<ProjectInfo>> cb) {
+    RestApi view = project(name).view("children");
+    if (recursive) {
+      view.addParameterTrue("recursive");
+    }
+    view.get(cb);
+  }
+
   public static void getDescription(Project.NameKey name,
       AsyncCallback<NativeString> cb) {
     project(name).view("description").get(cb);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectInfo.java
index 80c1feb..cab45b5 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectInfo.java
@@ -28,6 +28,12 @@
   public final native String name() /*-{ return this.name; }-*/;
   public final native String description() /*-{ return this.description; }-*/;
 
+  public final Project.State state() {
+    return Project.State.valueOf(getStringState());
+  }
+
+  private final native String getStringState() /*-{ return this.state; }-*/;
+
   @Override
   public final String getDisplayString() {
     if (description() != null) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/queryIcon.png b/gerrit-gwtui/src/main/java/com/google/gerrit/client/queryIcon.png
index 5aace51..5ebf2cb 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/queryIcon.png
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/queryIcon.png
Binary files differ
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/readOnly.png b/gerrit-gwtui/src/main/java/com/google/gerrit/client/readOnly.png
new file mode 100644
index 0000000..62e89f9
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/readOnly.png
Binary files differ
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/redNot.png b/gerrit-gwtui/src/main/java/com/google/gerrit/client/redNot.png
index 4e83a8f..99834fd 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/redNot.png
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/redNot.png
Binary files differ
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/NativeString.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/NativeString.java
index be4cfd6..a3dce43 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/NativeString.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/NativeString.java
@@ -19,10 +19,15 @@
 
 /** Wraps a String that was returned from a JSON API. */
 public final class NativeString extends JavaScriptObject {
-  private static final JavaScriptObject TYPE = init();
+  public static final JavaScriptObject TYPE = init();
 
-  private static final native JavaScriptObject init()
-  /*-{ return function(s){this.s=s} }-*/;
+  private static final native JavaScriptObject init() /*-{
+    var T = function(s){this.s=s};
+    T.prototype = {
+      get: function(){return this.s},
+    };
+    return T;
+  }-*/;
 
   static final NativeString wrap(String s) {
     return wrap0(TYPE, s);
@@ -32,7 +37,6 @@
   /*-{ return new T(s) }-*/;
 
   public final native String asString() /*-{ return this.s; }-*/;
-  private final native void set(String v) /*-{ this.s = v; }-*/;
 
   public static final AsyncCallback<NativeString>
   unwrap(final AsyncCallback<String> cb) {
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 4666d34..eeb45d4 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
@@ -336,6 +336,11 @@
     send(PUT, cb);
   }
 
+  public <T extends JavaScriptObject> void put(String content,
+      AsyncCallback<T> cb) {
+    sendRaw(PUT, content, cb);
+  }
+
   public <T extends JavaScriptObject> void put(
       JavaScriptObject content,
       AsyncCallback<T> cb) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ParentProjectBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ParentProjectBox.java
new file mode 100644
index 0000000..a03cb34
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ParentProjectBox.java
@@ -0,0 +1,101 @@
+// 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.client.ui;
+
+import com.google.gerrit.client.projects.ProjectApi;
+import com.google.gerrit.client.projects.ProjectInfo;
+import com.google.gerrit.client.rpc.Natives;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gwt.core.client.JsArray;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.SuggestBox;
+import com.google.gwtexpui.globalkey.client.NpTextBox;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class ParentProjectBox extends Composite {
+  private final NpTextBox textBox;
+  private final SuggestBox suggestBox;
+  private final ParentProjectNameSuggestOracle suggestOracle;
+
+  public ParentProjectBox() {
+    textBox = new NpTextBox();
+    suggestOracle = new ParentProjectNameSuggestOracle();
+    suggestBox = new SuggestBox(suggestOracle, textBox);
+    initWidget(suggestBox);
+  }
+
+  public void setVisibleLength(int len) {
+    textBox.setVisibleLength(len);
+  }
+
+  public void setProject(final Project.NameKey project) {
+    suggestOracle.setProject(project);
+  }
+
+  public void setParentProject(final Project.NameKey parent) {
+    suggestBox.setText(parent != null ? parent.get() : "");
+  }
+
+  public Project.NameKey getParentProjectName() {
+    final String projectName = suggestBox.getText().trim();
+    if (projectName.isEmpty()) {
+      return null;
+    }
+    return new Project.NameKey(projectName);
+  }
+
+  private static class ParentProjectNameSuggestOracle extends ProjectNameSuggestOracle {
+    private Set<String> exclude = new HashSet<String>();
+
+    public void setProject(Project.NameKey project) {
+      exclude.clear();
+      exclude.add(project.get());
+      ProjectApi.getChildren(project, true, new AsyncCallback<JsArray<ProjectInfo>>() {
+        @Override
+        public void onSuccess(JsArray<ProjectInfo> result) {
+          for (ProjectInfo p : Natives.asList(result)) {
+            exclude.add(p.name());
+          }
+        }
+
+        @Override
+        public void onFailure(Throwable caught) {
+        }
+      });
+    }
+
+    @Override
+    public void _onRequestSuggestions(Request req, final Callback callback) {
+      super._onRequestSuggestions(req, new Callback() {
+        public void onSuggestionsReady(Request request, Response response) {
+          if (exclude.size() > 0) {
+            Set<Suggestion> filteredSuggestions =
+                new HashSet<Suggestion>(response.getSuggestions());
+            for (Suggestion s : response.getSuggestions()) {
+              if (exclude.contains(s.getReplacementString())) {
+                filteredSuggestions.remove(s);
+              }
+            }
+            response.setSuggestions(filteredSuggestions);
+          }
+          callback.onSuggestionsReady(request, response);
+        }
+      });
+    }
+  }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectsTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectsTable.java
index a99348d..289e6fe 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectsTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectsTable.java
@@ -25,9 +25,10 @@
 import java.util.List;
 
 public class ProjectsTable extends NavigationTable<ProjectInfo> {
-  public static final int C_NAME = 1;
-  public static final int C_DESCRIPTION = 2;
-  public static final int C_REPO_BROWSER = 3;
+  public static final int C_STATE = 1;
+  public static final int C_NAME = 2;
+  public static final int C_DESCRIPTION = 3;
+  public static final int C_REPO_BROWSER = 4;
 
   public ProjectsTable() {
     super(Util.C.projectItemHelp());
@@ -35,10 +36,14 @@
   }
 
   protected void initColumnHeaders() {
+    table.setText(0, C_STATE, Util.C.projectStateAbbrev());
+    table.getCellFormatter().getElement(0, C_STATE)
+        .setTitle(Util.C.projectStateHelp());
     table.setText(0, C_NAME, Util.C.projectName());
     table.setText(0, C_DESCRIPTION, Util.C.projectDescription());
 
     final FlexCellFormatter fmt = table.getFlexCellFormatter();
+    fmt.addStyleName(0, C_STATE, Gerrit.RESOURCES.css().iconHeader());
     fmt.addStyleName(0, C_NAME, Gerrit.RESOURCES.css().dataHeader());
     fmt.addStyleName(0, C_DESCRIPTION, Gerrit.RESOURCES.css().dataHeader());
   }
@@ -78,6 +83,7 @@
     applyDataRowStyle(row);
 
     final FlexCellFormatter fmt = table.getFlexCellFormatter();
+    fmt.addStyleName(row, C_STATE, Gerrit.RESOURCES.css().iconCell());
     fmt.addStyleName(row, C_NAME, Gerrit.RESOURCES.css().dataCell());
     fmt.addStyleName(row, C_NAME, Gerrit.RESOURCES.css().projectNameColumn());
     fmt.addStyleName(row, C_DESCRIPTION, Gerrit.RESOURCES.css().dataCell());
@@ -86,6 +92,7 @@
   }
 
   protected void populate(final int row, final ProjectInfo k) {
+    table.setText(row, C_STATE, k.state().toString());
     table.setText(row, C_NAME, k.name());
     table.setText(row, C_DESCRIPTION, k.description());
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Screen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Screen.java
index 0cabdda..01a90e3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Screen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Screen.java
@@ -71,7 +71,7 @@
   }
 
   private static enum Cols {
-    West, Title, East, FarEast;
+    West, Title, East, FarEast
   }
 
   protected void onInitUI() {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/UIConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/UIConstants.java
index 1919cd3..bcfb394 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/UIConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/UIConstants.java
@@ -23,4 +23,6 @@
   String projectName();
   String projectDescription();
   String projectItemHelp();
+  String projectStateAbbrev();
+  String projectStateHelp();
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/UIConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/UIConstants.properties
index 8a72355..1e0e185 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/UIConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/UIConstants.properties
@@ -3,4 +3,6 @@
 
 projectName = Project Name
 projectDescription = Project Description
-projectItemHelp = project
\ No newline at end of file
+projectItemHelp = project
+projectStateAbbrev = S
+projectStateHelp = State
\ No newline at end of file
diff --git a/gerrit-gwtui/src/main/java/net/codemirror/lib/CodeMirror.java b/gerrit-gwtui/src/main/java/net/codemirror/lib/CodeMirror.java
index 96daa49..2ebe326 100644
--- a/gerrit-gwtui/src/main/java/net/codemirror/lib/CodeMirror.java
+++ b/gerrit-gwtui/src/main/java/net/codemirror/lib/CodeMirror.java
@@ -68,7 +68,7 @@
   }-*/;
 
   public enum LineClassWhere {
-    TEXT, BACKGROUND, WRAP;
+    TEXT, BACKGROUND, WRAP
   }
 
   public final void addLineClass(int line, LineClassWhere where,
@@ -201,7 +201,7 @@
 
   public final FromTo getSelectedRange() {
     return FromTo.create(getCursor("start"), getCursor("end"));
-  };
+  }
 
   public final native void setCursor(LineCharacter lineCh) /*-{
     this.setCursor(lineCh);
@@ -277,11 +277,6 @@
     return this.display.scrollbarV;
   }-*/;
 
-  public static final native void setObjectProperty(JavaScriptObject obj,
-      String name, boolean value) /*-{
-    obj[name] = value;
-  }-*/;
-
   public static final native KeyMap cloneKeyMap(String name) /*-{
     var i = $wnd.CodeMirror.keyMap[name];
     var o = {};
@@ -291,6 +286,10 @@
     return o;
   }-*/;
 
+  public final native void execCommand(String cmd) /*-{
+    this.execCommand(cmd);
+  }-*/;
+
   public static final native void addKeyMap(String name, KeyMap km) /*-{
     $wnd.CodeMirror.keyMap[name] = km;
   }-*/;
diff --git a/gerrit-gwtui/src/main/java/net/codemirror/lib/Loader.java b/gerrit-gwtui/src/main/java/net/codemirror/lib/Loader.java
index 46e7a71..d2954ba 100644
--- a/gerrit-gwtui/src/main/java/net/codemirror/lib/Loader.java
+++ b/gerrit-gwtui/src/main/java/net/codemirror/lib/Loader.java
@@ -90,7 +90,8 @@
   private static void initVimKeys() {
     // TODO: Better custom keybindings, remove temporary navigation hacks.
     KeyMap km = CodeMirror.cloneKeyMap("vim");
-    for (String s : new String[] {"A", "C", "O", "R", "U", "Ctrl-C"}) {
+    for (String s : new String[] {
+        "A", "C", "O", "R", "U", "Ctrl-C", "Ctrl-O"}) {
       km.remove(s);
     }
     CodeMirror.addKeyMap("vim_ro", km);
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/CookieBase64.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/CookieBase64.java
index 3bcdcd2..fab9f1b 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/CookieBase64.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/CookieBase64.java
@@ -33,8 +33,9 @@
   }
 
   private static int fill(final char[] out, int o, final char f, final int l) {
-    for (char c = f; c <= l; c++)
+    for (char c = f; c <= l; c++) {
       out[o++] = c;
+    }
     return o;
   }
 
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 79aca6d..61ea464 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
@@ -127,7 +127,7 @@
         cfg, "change", null, "updateDelay", 30, TimeUnit.SECONDS));
     config.setChangeScreen(cfg.getEnum(
         "gerrit", null, "changeScreen",
-        AccountGeneralPreferences.ChangeScreen.OLD_UI));
+        AccountGeneralPreferences.ChangeScreen.CHANGE_SCREEN2));
 
     config.setReportBugUrl(cfg.getString("gerrit", null, "reportBugUrl"));
     if (config.getReportBugUrl() == null) {
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java
index 5593baf..3443968 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java
@@ -31,7 +31,6 @@
 import com.google.gerrit.server.RemotePeer;
 import com.google.gerrit.server.config.AuthConfig;
 import com.google.gerrit.server.config.CanonicalWebUrl;
-import com.google.gerrit.server.config.FactoryModule;
 import com.google.gerrit.server.config.GerritRequestModule;
 import com.google.gerrit.server.contact.ContactStore;
 import com.google.gerrit.server.contact.ContactStoreProvider;
@@ -46,7 +45,7 @@
 
 import java.net.SocketAddress;
 
-public class WebModule extends FactoryModule {
+public class WebModule extends LifecycleModule {
   private final AuthConfig authConfig;
   private final UrlModule.UrlConfig urlConfig;
   private final boolean wantSSL;
@@ -132,11 +131,6 @@
     bind(SocketAddress.class).annotatedWith(RemotePeer.class).toProvider(
         HttpRemotePeerProvider.class).in(RequestScoped.class);
 
-    install(new LifecycleModule() {
-      @Override
-      protected void configure() {
-        listener().toInstance(registerInParentInjectors());
-      }
-    });
+    listener().toInstance(registerInParentInjectors());
   }
 }
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java
index 53abc4c..b2972d9 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java
@@ -81,6 +81,8 @@
   private static final long serialVersionUID = 1L;
   private static final Logger log
       = LoggerFactory.getLogger(HttpPluginServlet.class);
+  private static final String PLUGINS_PREFIX = "/plugins/";
+  private static final String AUTHORIZED_PREFIX = "/a" + PLUGINS_PREFIX;
 
   private final MimeUtilFileTypeRegistry mimeUtil;
   private final Provider<String> webUrl;
@@ -91,6 +93,7 @@
 
   private List<Plugin> pending = Lists.newArrayList();
   private String base;
+  private String authorizedBase;
   private final ConcurrentMap<String, PluginHolder> plugins
       = Maps.newConcurrentMap();
 
@@ -129,7 +132,8 @@
     super.init(config);
 
     String path = config.getServletContext().getContextPath();
-    base = Strings.nullToEmpty(path) + "/plugins/";
+    base = Strings.nullToEmpty(path) + PLUGINS_PREFIX;
+    authorizedBase = Strings.nullToEmpty(path) + AUTHORIZED_PREFIX;
     for (Plugin plugin : pending) {
       install(plugin);
     }
@@ -213,7 +217,8 @@
       return;
     }
 
-    WrappedRequest wr = new WrappedRequest(req, base + name);
+    WrappedRequest wr = new WrappedRequest(req,
+        (isAuthorizedCall(req) ? authorizedBase : base) + name);
     FilterChain chain = new FilterChain() {
       @Override
       public void doFilter(ServletRequest req, ServletResponse res)
@@ -228,6 +233,11 @@
     }
   }
 
+  private boolean isAuthorizedCall(HttpServletRequest req) {
+    return !Strings.isNullOrEmpty(req.getServletPath())
+        && req.getServletPath().startsWith(AUTHORIZED_PREFIX);
+  }
+
   private static boolean isApiCall(HttpServletRequest req, List<String> parts) {
     String method = req.getMethod();
     int cnt = parts.size();
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/ChangeListServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/ChangeListServiceImpl.java
deleted file mode 100644
index 0b54db1..0000000
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/ChangeListServiceImpl.java
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright (C) 2008 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.httpd.rpc;
-
-import com.google.gerrit.common.data.ChangeListService;
-import com.google.gerrit.common.data.ToggleStarRequest;
-import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.reviewdb.client.StarredChange;
-import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gerrit.server.CurrentUser;
-import com.google.gwtjsonrpc.common.AsyncCallback;
-import com.google.gwtjsonrpc.common.VoidResult;
-import com.google.gwtorm.server.OrmException;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-
-public class ChangeListServiceImpl extends BaseServiceImplementation implements
-    ChangeListService {
-  private final Provider<CurrentUser> currentUser;
-
-  @Inject
-  ChangeListServiceImpl(final Provider<ReviewDb> schema,
-      final Provider<CurrentUser> currentUser) {
-    super(schema, currentUser);
-    this.currentUser = currentUser;
-  }
-
-  public void toggleStars(final ToggleStarRequest req,
-      final AsyncCallback<VoidResult> callback) {
-    run(callback, new Action<VoidResult>() {
-      public VoidResult run(final ReviewDb db) throws OrmException {
-        final Account.Id me = getAccountId();
-        final Set<Change.Id> existing = currentUser.get().getStarredChanges();
-        List<StarredChange> add = new ArrayList<StarredChange>();
-        List<StarredChange.Key> remove = new ArrayList<StarredChange.Key>();
-
-        if (req.getAddSet() != null) {
-          for (final Change.Id id : req.getAddSet()) {
-            if (!existing.contains(id)) {
-              add.add(new StarredChange(new StarredChange.Key(me, id)));
-            }
-          }
-        }
-
-        if (req.getRemoveSet() != null) {
-          for (final Change.Id id : req.getRemoveSet()) {
-            remove.add(new StarredChange.Key(me, id));
-          }
-        }
-
-        db.starredChanges().insert(add);
-        db.starredChanges().deleteKeys(remove);
-        return VoidResult.INSTANCE;
-      }
-    });
-  }
-}
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/UiRpcModule.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/UiRpcModule.java
index 7de332a..08e1582 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/UiRpcModule.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/UiRpcModule.java
@@ -27,7 +27,6 @@
 
   @Override
   protected void configureServlets() {
-    rpc(ChangeListServiceImpl.class);
     rpc(SuggestServiceImpl.class);
     rpc(SystemInfoServiceImpl.class);
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ChangeProjectAccess.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ChangeProjectAccess.java
index 0dd3d16..57be31e 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ChangeProjectAccess.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ChangeProjectAccess.java
@@ -19,12 +19,15 @@
 import com.google.gerrit.common.data.ProjectAccess;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.account.GroupBackend;
+import com.google.gerrit.server.config.AllProjectsNameProvider;
 import com.google.gerrit.server.git.MetaDataUpdate;
 import com.google.gerrit.server.git.ProjectConfig;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.project.ProjectControl;
+import com.google.gerrit.server.project.SetParent;
 import com.google.inject.Inject;
+import com.google.inject.Provider;
 import com.google.inject.assistedinject.Assisted;
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
@@ -35,9 +38,11 @@
 
 class ChangeProjectAccess extends ProjectAccessHandler<ProjectAccess> {
   interface Factory {
-    ChangeProjectAccess create(@Assisted Project.NameKey projectName,
+    ChangeProjectAccess create(
+        @Assisted("projectName") Project.NameKey projectName,
         @Nullable @Assisted ObjectId base,
         @Assisted List<AccessSection> sectionList,
+        @Nullable @Assisted("parentProjectName") Project.NameKey parentProjectName,
         @Nullable @Assisted String message);
   }
 
@@ -45,17 +50,21 @@
   private final ProjectCache projectCache;
 
   @Inject
-  ChangeProjectAccess(final ProjectAccessFactory.Factory projectAccessFactory,
-      final ProjectControl.Factory projectControlFactory,
-      final ProjectCache projectCache, final GroupBackend groupBackend,
-      final MetaDataUpdate.User metaDataUpdateFactory,
+  ChangeProjectAccess(ProjectAccessFactory.Factory projectAccessFactory,
+      ProjectControl.Factory projectControlFactory,
+      ProjectCache projectCache, GroupBackend groupBackend,
+      MetaDataUpdate.User metaDataUpdateFactory,
+      AllProjectsNameProvider allProjects,
+      Provider<SetParent> setParent,
 
-      @Assisted final Project.NameKey projectName,
-      @Nullable @Assisted final ObjectId base,
+      @Assisted("projectName") Project.NameKey projectName,
+      @Nullable @Assisted ObjectId base,
       @Assisted List<AccessSection> sectionList,
+      @Nullable @Assisted("parentProjectName") Project.NameKey parentProjectName,
       @Nullable @Assisted String message) {
     super(projectControlFactory, groupBackend, metaDataUpdateFactory,
-        projectName, base, sectionList, message, true);
+        allProjects, setParent, projectName, base, sectionList,
+        parentProjectName, message, true);
     this.projectAccessFactory = projectAccessFactory;
     this.projectCache = projectCache;
   }
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 2c5681b..6e7150d 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
@@ -203,6 +203,8 @@
     detail.setOwnerOf(ownerOf);
     detail.setCanUpload(pc.isOwner()
         || (metaConfigControl.isVisible() && metaConfigControl.canUpload()));
+    detail.setCanChangeParent(pc.getCurrentUser().getCapabilities()
+        .canAdministrateServer());
     detail.setConfigVisible(pc.isOwner() || metaConfigControl.isVisible());
     detail.setLabelTypes(pc.getLabelTypes());
     return detail;
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 0a50a38..971c4b3 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
@@ -22,16 +22,23 @@
 import com.google.gerrit.common.data.PermissionRule;
 import com.google.gerrit.common.errors.InvalidNameException;
 import com.google.gerrit.common.errors.NoSuchGroupException;
+import com.google.gerrit.common.errors.UpdateParentFailedException;
+import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.ResourceConflictException;
+import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
 import com.google.gerrit.httpd.rpc.Handler;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.account.GroupBackend;
 import com.google.gerrit.server.account.GroupBackends;
+import com.google.gerrit.server.config.AllProjectsNameProvider;
 import com.google.gerrit.server.git.MetaDataUpdate;
 import com.google.gerrit.server.git.ProjectConfig;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.ProjectControl;
 import com.google.gerrit.server.project.RefControl;
+import com.google.gerrit.server.project.SetParent;
 import com.google.gwtorm.server.OrmException;
+import com.google.inject.Provider;
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
@@ -47,27 +54,32 @@
   private final ProjectControl.Factory projectControlFactory;
   protected final GroupBackend groupBackend;
   private final MetaDataUpdate.User metaDataUpdateFactory;
+  private final AllProjectsNameProvider allProjects;
+  private final Provider<SetParent> setParent;
 
   protected final Project.NameKey projectName;
   protected final ObjectId base;
   private List<AccessSection> sectionList;
+  private final Project.NameKey parentProjectName;
   protected String message;
   private boolean checkIfOwner;
 
-  protected ProjectAccessHandler(
-      final ProjectControl.Factory projectControlFactory,
-      final GroupBackend groupBackend,
-      final MetaDataUpdate.User metaDataUpdateFactory,
-      final Project.NameKey projectName, final ObjectId base,
-      final List<AccessSection> sectionList, final String message,
-      final boolean checkIfOwner) {
+  protected ProjectAccessHandler(ProjectControl.Factory projectControlFactory,
+      GroupBackend groupBackend, MetaDataUpdate.User metaDataUpdateFactory,
+      AllProjectsNameProvider allProjects, Provider<SetParent> setParent,
+      Project.NameKey projectName, ObjectId base,
+      List<AccessSection> sectionList, Project.NameKey parentProjectName,
+      String message, boolean checkIfOwner) {
     this.projectControlFactory = projectControlFactory;
     this.groupBackend = groupBackend;
     this.metaDataUpdateFactory = metaDataUpdateFactory;
+    this.allProjects = allProjects;
+    this.setParent = setParent;
 
     this.projectName = projectName;
     this.base = base;
     this.sectionList = sectionList;
+    this.parentProjectName = parentProjectName;
     this.message = message;
     this.checkIfOwner = checkIfOwner;
   }
@@ -75,7 +87,7 @@
   @Override
   public final T call() throws NoSuchProjectException, IOException,
       ConfigInvalidException, InvalidNameException, NoSuchGroupException,
-      OrmException {
+      OrmException, UpdateParentFailedException {
     final ProjectControl projectControl =
         projectControlFactory.controlFor(projectName);
 
@@ -120,6 +132,20 @@
         }
       }
 
+      if (!config.getProject().getNameKey().equals(allProjects.get()) &&
+          !config.getProject().getParent(allProjects.get()).equals(parentProjectName)) {
+        try {
+          setParent.get().validateParentUpdate(projectControl, parentProjectName.get());
+        } catch (AuthException e) {
+          throw new UpdateParentFailedException(e.getMessage(), e);
+        } catch (ResourceConflictException e) {
+          throw new UpdateParentFailedException(e.getMessage(), e);
+        } catch (UnprocessableEntityException e) {
+          throw new UpdateParentFailedException(e.getMessage(), e);
+        }
+        config.getProject().setParentName(parentProjectName);
+      }
+
       if (message != null && !message.isEmpty()) {
         if (!message.endsWith("\n")) {
           message += "\n";
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAdminServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAdminServiceImpl.java
index 66ba75c..c378701 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAdminServiceImpl.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAdminServiceImpl.java
@@ -56,14 +56,16 @@
   @Override
   public void changeProjectAccess(Project.NameKey projectName,
       String baseRevision, String msg, List<AccessSection> sections,
-      AsyncCallback<ProjectAccess> cb) {
-    changeProjectAccessFactory.create(projectName, getBase(baseRevision), sections, msg).to(cb);
+      Project.NameKey parentProjectName, AsyncCallback<ProjectAccess> cb) {
+    changeProjectAccessFactory.create(projectName, getBase(baseRevision),
+        sections, parentProjectName, msg).to(cb);
   }
 
   @Override
   public void reviewProjectAccess(Project.NameKey projectName,
       String baseRevision, String msg, List<AccessSection> sections,
-      AsyncCallback<Change.Id> cb) {
-    reviewProjectAccessFactory.create(projectName, getBase(baseRevision), sections, msg).to(cb);
+      Project.NameKey parentProjectName, AsyncCallback<Change.Id> cb) {
+    reviewProjectAccessFactory.create(projectName, getBase(baseRevision),
+        sections, parentProjectName, msg).to(cb);
   }
 }
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 3681888..3f4030d 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
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.httpd.rpc.project;
 
+import com.google.gerrit.common.ChangeHooks;
 import com.google.gerrit.common.Nullable;
 import com.google.gerrit.common.data.AccessSection;
 import com.google.gerrit.reviewdb.client.AccountGroup;
@@ -30,13 +31,16 @@
 import com.google.gerrit.server.account.GroupBackend;
 import com.google.gerrit.server.change.ChangeResource;
 import com.google.gerrit.server.change.PostReviewers;
+import com.google.gerrit.server.config.AllProjectsNameProvider;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.MetaDataUpdate;
 import com.google.gerrit.server.git.ProjectConfig;
 import com.google.gerrit.server.index.ChangeIndexer;
+import com.google.gerrit.server.mail.CreateChangeSender;
 import com.google.gerrit.server.patch.PatchSetInfoFactory;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.ProjectControl;
+import com.google.gerrit.server.project.SetParent;
 import com.google.gerrit.server.util.TimeUtil;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
@@ -45,6 +49,8 @@
 
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.revwalk.RevCommit;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -52,10 +58,15 @@
 import java.util.List;
 
 public class ReviewProjectAccess extends ProjectAccessHandler<Change.Id> {
+  private static final Logger log =
+      LoggerFactory.getLogger(ReviewProjectAccess.class);
+
   interface Factory {
-    ReviewProjectAccess create(@Assisted Project.NameKey projectName,
+    ReviewProjectAccess create(
+        @Assisted("projectName") Project.NameKey projectName,
         @Nullable @Assisted ObjectId base,
         @Assisted List<AccessSection> sectionList,
+        @Nullable @Assisted("parentProjectName") Project.NameKey parentProjectName,
         @Nullable @Assisted String message);
   }
 
@@ -65,6 +76,8 @@
   private final Provider<PostReviewers> reviewersProvider;
   private final ChangeControl.GenericFactory changeFactory;
   private final ChangeIndexer indexer;
+  private final ChangeHooks hooks;
+  private final CreateChangeSender.Factory createChangeSenderFactory;
 
   @Inject
   ReviewProjectAccess(final ProjectControl.Factory projectControlFactory,
@@ -73,20 +86,27 @@
       IdentifiedUser user, PatchSetInfoFactory patchSetInfoFactory,
       Provider<PostReviewers> reviewersProvider,
       ChangeControl.GenericFactory changeFactory,
-      ChangeIndexer indexer,
+      ChangeIndexer indexer, ChangeHooks hooks,
+      CreateChangeSender.Factory createChangeSenderFactory,
+      AllProjectsNameProvider allProjects,
+      Provider<SetParent> setParent,
 
-      @Assisted Project.NameKey projectName,
+      @Assisted("projectName") Project.NameKey projectName,
       @Nullable @Assisted ObjectId base,
       @Assisted List<AccessSection> sectionList,
+      @Nullable @Assisted("parentProjectName") Project.NameKey parentProjectName,
       @Nullable @Assisted String message) {
     super(projectControlFactory, groupBackend, metaDataUpdateFactory,
-        projectName, base, sectionList, message, false);
+        allProjects, setParent, projectName, base, sectionList,
+        parentProjectName, message, false);
     this.db = db;
     this.user = user;
     this.patchSetInfoFactory = patchSetInfoFactory;
     this.reviewersProvider = reviewersProvider;
     this.changeFactory = changeFactory;
     this.indexer = indexer;
+    this.hooks = hooks;
+    this.createChangeSenderFactory = createChangeSenderFactory;
   }
 
   @Override
@@ -122,12 +142,22 @@
       insertAncestors(ps.getId(), commit);
       db.patchSets().insert(Collections.singleton(ps));
       db.changes().insert(Collections.singleton(change));
-      addProjectOwnersAsReviewers(change);
       db.commit();
     } finally {
       db.rollback();
     }
     indexer.index(change);
+    hooks.doPatchsetCreatedHook(change, ps, db);
+    try {
+      CreateChangeSender cm =
+          createChangeSenderFactory.create(change);
+      cm.setFrom(change.getOwner());
+      cm.setPatchSet(ps, info);
+      cm.send();
+    } catch (Exception err) {
+      log.error("Cannot send email for new change " + change.getId(), err);
+    }
+    addProjectOwnersAsReviewers(change);
     return changeId;
   }
 
diff --git a/gerrit-httpd/src/test/java/com/google/gerrit/httpd/GitWebConfigTest.java b/gerrit-httpd/src/test/java/com/google/gerrit/httpd/GitWebConfigTest.java
index c834b94..26cdd8a 100644
--- a/gerrit-httpd/src/test/java/com/google/gerrit/httpd/GitWebConfigTest.java
+++ b/gerrit-httpd/src/test/java/com/google/gerrit/httpd/GitWebConfigTest.java
@@ -14,19 +14,24 @@
 
 package com.google.gerrit.httpd;
 
-import junit.framework.TestCase;
+import org.junit.Test;
 
-public class GitWebConfigTest extends TestCase {
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class GitWebConfigTest {
 
   private static final String VALID_CHARACTERS = "*()";
   private static final String SOME_INVALID_CHARACTERS = "09AZaz$-_.+!',";
 
+  @Test
   public void testValidPathSeparator() {
     for(char c : VALID_CHARACTERS.toCharArray()) {
       assertTrue("valid character rejected: " + c, GitWebConfig.isValidPathSeparator(c));
     }
   }
 
+  @Test
   public void testInalidPathSeparator() {
     for(char c : SOME_INVALID_CHARACTERS.toCharArray()) {
       assertFalse("invalid character accepted: " + c, GitWebConfig.isValidPathSeparator(c));
diff --git a/gerrit-httpd/src/test/java/com/google/gerrit/httpd/restapi/ParameterParserTest.java b/gerrit-httpd/src/test/java/com/google/gerrit/httpd/restapi/ParameterParserTest.java
index ffbc7f3..8533a9c 100644
--- a/gerrit-httpd/src/test/java/com/google/gerrit/httpd/restapi/ParameterParserTest.java
+++ b/gerrit-httpd/src/test/java/com/google/gerrit/httpd/restapi/ParameterParserTest.java
@@ -21,9 +21,11 @@
 import com.google.gson.JsonObject;
 import com.google.gson.JsonPrimitive;
 
-import junit.framework.TestCase;
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
 
-public class ParameterParserTest extends TestCase {
+public class ParameterParserTest {
+  @Test
   public void testConvertFormToJson() throws BadRequestException {
     JsonObject obj = ParameterParser.formToJson(
         ImmutableMap.of(
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 44226bc..3ca3619 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
@@ -190,7 +190,7 @@
     try {
       path = getDistributionArchive();
     } catch (FileNotFoundException e) {
-      if (NOT_ARCHIVED == e.getMessage()) {
+      if (NOT_ARCHIVED.equals(e.getMessage())) {
         // Assume the CLASSPATH was made complete by the calling process,
         // as we are likely being run from within a developer's IDE.
         //
diff --git a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneIndexModule.java b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneIndexModule.java
index ef96374..583e54f 100644
--- a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneIndexModule.java
+++ b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneIndexModule.java
@@ -16,7 +16,6 @@
 
 import com.google.gerrit.extensions.events.LifecycleListener;
 import com.google.gerrit.lifecycle.LifecycleModule;
-import com.google.gerrit.server.config.FactoryModule;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.gerrit.server.index.ChangeSchemas;
 import com.google.gerrit.server.index.IndexCollection;
@@ -45,12 +44,7 @@
 
   @Override
   protected void configure() {
-    install(new FactoryModule() {
-      @Override
-      public void configure() {
-        factory(LuceneChangeIndex.Factory.class);
-      }
-    });
+    factory(LuceneChangeIndex.Factory.class);
     install(new IndexModule(threads));
     if (singleVersion == null && base == null) {
       install(new MultiVersionModule());
@@ -62,12 +56,7 @@
   private class MultiVersionModule extends LifecycleModule {
     @Override
     public void configure() {
-      install(new FactoryModule() {
-        @Override
-        public void configure() {
-          factory(OnlineReindexer.Factory.class);
-        }
-      });
+      factory(OnlineReindexer.Factory.class);
       listener().to(LuceneVersionManager.class);
     }
   }
diff --git a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/DiscoveryResult.java b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/DiscoveryResult.java
index 711f29a..37051da 100644
--- a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/DiscoveryResult.java
+++ b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/DiscoveryResult.java
@@ -25,7 +25,7 @@
     NO_PROVIDER,
 
     /** The provider was discovered, but something else failed. */
-    ERROR;
+    ERROR
   }
 
   Status status;
diff --git a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/SignInMode.java b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/SignInMode.java
index b6a9857..9aae6c5 100644
--- a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/SignInMode.java
+++ b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/SignInMode.java
@@ -15,5 +15,5 @@
 package com.google.gerrit.httpd.auth.openid;
 
 enum SignInMode {
-  SIGN_IN, LINK_IDENTIY, REGISTER;
+  SIGN_IN, LINK_IDENTIY, REGISTER
 }
diff --git a/gerrit-patch-jgit/BUCK b/gerrit-patch-jgit/BUCK
index 18890ac..1e0953f 100644
--- a/gerrit-patch-jgit/BUCK
+++ b/gerrit-patch-jgit/BUCK
@@ -30,3 +30,15 @@
   ],
   visibility = ['PUBLIC'],
 )
+
+java_test(
+  name = 'jgit_patch_tests',
+  srcs = glob(['src/test/java/**/*.java']),
+  deps = [
+    ':server',
+    '//lib/jgit:jgit',
+    '//lib:junit',
+  ],
+  source_under_test = [':server'],
+  visibility = ['//tools/eclipse:classpath'],
+)
diff --git a/gerrit-patch-jgit/src/main/java/org/eclipse/jgit/internal/storage/file/WindowCacheStatAccessor.java b/gerrit-patch-jgit/src/main/java/org/eclipse/jgit/internal/storage/file/WindowCacheStatAccessor.java
index f241daa..1e94050 100644
--- a/gerrit-patch-jgit/src/main/java/org/eclipse/jgit/internal/storage/file/WindowCacheStatAccessor.java
+++ b/gerrit-patch-jgit/src/main/java/org/eclipse/jgit/internal/storage/file/WindowCacheStatAccessor.java
@@ -14,8 +14,6 @@
 
 package org.eclipse.jgit.internal.storage.file;
 
-import org.eclipse.jgit.internal.storage.file.WindowCache;
-
 // Hack to obtain visibility to package level methods only.
 // These aren't yet part of the public JGit API.
 
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java b/gerrit-patch-jgit/src/test/java/org/eclipse/jgit/diff/EditDeserializerTest.java
similarity index 64%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
rename to gerrit-patch-jgit/src/test/java/org/eclipse/jgit/diff/EditDeserializerTest.java
index a5371d2..f0ad62a 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
+++ b/gerrit-patch-jgit/src/test/java/org/eclipse/jgit/diff/EditDeserializerTest.java
@@ -12,19 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.acceptance.rest.change;
+package org.eclipse.jgit.diff;
 
-import com.google.common.collect.Maps;
+import org.junit.Test;
+import static org.junit.Assert.assertNotNull;
 
-import java.util.Map;
-
-public class ReviewInput {
-  Map<String, Integer> labels;
-
-  public static ReviewInput approve() {
-    ReviewInput in = new ReviewInput();
-    in.labels = Maps.newHashMap();
-    in.labels.put("Code-Review", 2);
-    return in;
+public class EditDeserializerTest {
+  @Test
+  public void testDiffDeserializer() {
+    assertNotNull("edit deserializer", new EditDeserializer());
   }
 }
diff --git a/gerrit-pgm/BUCK b/gerrit-pgm/BUCK
index d3a8408..8915353 100644
--- a/gerrit-pgm/BUCK
+++ b/gerrit-pgm/BUCK
@@ -68,7 +68,10 @@
     '//lib:gwtorm',
   ],
   compile_deps = ['//gerrit-launcher:launcher'],
-  visibility = ['//gerrit-war:'],
+  visibility = [
+    '//gerrit-war:',
+    '//gerrit-acceptance-tests/...',
+  ],
 )
 
 java_library2(
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 35d8e76..aee16da 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
@@ -138,6 +138,7 @@
   private Injector httpdInjector;
   private File runFile;
   private boolean test;
+  private AbstractModule luceneModule;
 
   private Runnable serverStarted;
 
@@ -226,6 +227,7 @@
         shell.set("m", manager);
         shell.set("ds", dbInjector.getInstance(DataSourceProvider.class));
         shell.set("schk", dbInjector.getInstance(SchemaVersionCheck.class));
+        shell.set("d", this);
         shell.run();
       } else {
         RuntimeShutdown.waitFor();
@@ -250,6 +252,12 @@
   }
 
   @VisibleForTesting
+  public void setLuceneModule(LuceneIndexModule m) {
+    luceneModule = m;
+    test = true;
+  }
+
+  @VisibleForTesting
   public void start() {
     if (dbInjector == null) {
       dbInjector = createDbInjector(MULTI_USER);
@@ -303,7 +311,7 @@
     AbstractModule changeIndexModule;
     switch (IndexModule.getIndexType(cfgInjector)) {
       case LUCENE:
-        changeIndexModule = new LuceneIndexModule();
+        changeIndexModule = luceneModule != null ? luceneModule : new LuceneIndexModule();
         break;
       case SOLR:
         changeIndexModule = new SolrIndexModule();
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/HiddenErrorHandler.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/HiddenErrorHandler.java
index e086e6a..9fd8929 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/HiddenErrorHandler.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/HiddenErrorHandler.java
@@ -65,8 +65,9 @@
 
   private static byte[] message(AbstractHttpConnection conn) {
     String msg = conn.getResponse().getReason();
-    if (msg == null)
+    if (msg == null) {
       msg = HttpStatus.getMessage(conn.getResponse().getStatus());
+    }
     return msg.getBytes(Charsets.ISO_8859_1);
   }
 
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyModule.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyModule.java
index 1ae9355..b563349 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyModule.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyModule.java
@@ -15,9 +15,8 @@
 package com.google.gerrit.pgm.http.jetty;
 
 import com.google.gerrit.lifecycle.LifecycleModule;
-import com.google.inject.AbstractModule;
 
-public class JettyModule extends AbstractModule {
+public class JettyModule extends LifecycleModule {
   private final JettyEnv env;
 
   public JettyModule(final JettyEnv env) {
@@ -28,11 +27,6 @@
   protected void configure() {
     bind(JettyEnv.class).toInstance(env);
     bind(JettyServer.class);
-    install(new LifecycleModule() {
-      @Override
-      protected void configure() {
-        listener().to(JettyServer.Lifecycle.class);
-      }
-    });
+    listener().to(JettyServer.Lifecycle.class);
   }
 }
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/ConsoleUI.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/ConsoleUI.java
index e8cf0ab..9af95ab 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/ConsoleUI.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/ConsoleUI.java
@@ -179,7 +179,7 @@
         }
         console.printf("       Supported options are:\n");
         for (final String v : allowedValues) {
-          console.printf("         %s\n", v.toString().toLowerCase());
+          console.printf("         %s\n", v.toLowerCase());
         }
       }
     }
diff --git a/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/LibrariesTest.java b/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/LibrariesTest.java
index df1f447..9ffcf6b 100644
--- a/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/LibrariesTest.java
+++ b/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/LibrariesTest.java
@@ -21,13 +21,14 @@
 import com.google.gerrit.pgm.util.ConsoleUI;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.inject.Provider;
-
-import junit.framework.TestCase;
+import org.junit.Test;
+import static org.junit.Assert.assertNotNull;
 
 import java.io.File;
 import java.io.FileNotFoundException;
 
-public class LibrariesTest extends TestCase {
+public class LibrariesTest {
+  @Test
   public void testCreate() throws FileNotFoundException {
     final SitePaths site = new SitePaths(new File("."));
     final ConsoleUI ui = createStrictMock(ConsoleUI.class);
diff --git a/gerrit-plugin-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml b/gerrit-plugin-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml
index ce8fa1a..21f508b 100644
--- a/gerrit-plugin-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml
+++ b/gerrit-plugin-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml
@@ -28,8 +28,12 @@
       <defaultValue>Y</defaultValue>
     </requiredProperty>
 
-    <requiredProperty key="Implementation-Vendor"/>
-    <requiredProperty key="Implementation-Url"/>
+    <requiredProperty key="Implementation-Vendor">
+      <defaultValue>Gerrit Code Review</defaultValue>
+    </requiredProperty>
+    <requiredProperty key="Implementation-Url">
+      <defaultValue>http://code.google.com/p/gerrit/</defaultValue>
+    </requiredProperty>
 
     <requiredProperty key="gerritApiType">
       <defaultValue>plugin</defaultValue>
@@ -58,6 +62,7 @@
       <directory></directory>
       <includes>
         <include>.gitignore</include>
+        <include>.settings/*</include>
         <include>LICENSE</include>
       </includes>
     </fileSet>
diff --git a/gerrit-plugin-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.core.resources.prefs b/gerrit-plugin-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..f15f85d
--- /dev/null
+++ b/gerrit-plugin-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,5 @@
+#Tue May 15 09:19:33 PDT 2012
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding//src/test/java=UTF-8
+encoding//src/test/resources=UTF-8
diff --git a/gerrit-plugin-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.core.runtime.prefs b/gerrit-plugin-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..8667cfd
--- /dev/null
+++ b/gerrit-plugin-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,3 @@
+#Tue Sep 02 16:59:24 PDT 2008
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/gerrit-plugin-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.core.prefs b/gerrit-plugin-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..2f45466
--- /dev/null
+++ b/gerrit-plugin-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,264 @@
+#Fri Jul 16 23:39:13 PDT 2010
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.6
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=16
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=0
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=0
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=2
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=true
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=80
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=true
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=80
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=3
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=false
+org.eclipse.jdt.core.formatter.tabulation.char=space
+org.eclipse.jdt.core.formatter.tabulation.size=2
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
diff --git a/gerrit-plugin-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.ui.prefs b/gerrit-plugin-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..d4218a5
--- /dev/null
+++ b/gerrit-plugin-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,61 @@
+#Wed Jul 29 11:31:38 PDT 2009
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_Google Format
+formatter_settings_version=11
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=com.google;com;junit;net;org;java;javax;
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates/>
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=false
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=false
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=false
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_trailing_whitespaces=true
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
+sp_cleanup.remove_unnecessary_casts=false
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_blocks=false
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=false
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=false
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
diff --git a/gerrit-plugin-archetype/src/main/resources/archetype-resources/pom.xml b/gerrit-plugin-archetype/src/main/resources/archetype-resources/pom.xml
index cbf8a52..cbdb9a2 100644
--- a/gerrit-plugin-archetype/src/main/resources/archetype-resources/pom.xml
+++ b/gerrit-plugin-archetype/src/main/resources/archetype-resources/pom.xml
@@ -1,5 +1,5 @@
 <!--
-Copyright (C) 2012 The Android Open Source Project
+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.
diff --git a/gerrit-plugin-archetype/src/main/resources/archetype-resources/src/main/java/HttpModule.java b/gerrit-plugin-archetype/src/main/resources/archetype-resources/src/main/java/HttpModule.java
index 2840112..69949ca 100644
--- a/gerrit-plugin-archetype/src/main/resources/archetype-resources/src/main/java/HttpModule.java
+++ b/gerrit-plugin-archetype/src/main/resources/archetype-resources/src/main/java/HttpModule.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2012 The Android Open Source Project
+// 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.
diff --git a/gerrit-plugin-archetype/src/main/resources/archetype-resources/src/main/java/Module.java b/gerrit-plugin-archetype/src/main/resources/archetype-resources/src/main/java/Module.java
index 0d28349..e9668d8 100644
--- a/gerrit-plugin-archetype/src/main/resources/archetype-resources/src/main/java/Module.java
+++ b/gerrit-plugin-archetype/src/main/resources/archetype-resources/src/main/java/Module.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2012 The Android Open Source Project
+// 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.
diff --git a/gerrit-plugin-archetype/src/main/resources/archetype-resources/src/main/java/SshModule.java b/gerrit-plugin-archetype/src/main/resources/archetype-resources/src/main/java/SshModule.java
index aa15ca5..fca5112 100644
--- a/gerrit-plugin-archetype/src/main/resources/archetype-resources/src/main/java/SshModule.java
+++ b/gerrit-plugin-archetype/src/main/resources/archetype-resources/src/main/java/SshModule.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2012 The Android Open Source Project
+// 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.
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 78f2941..f619f91 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
@@ -18,9 +18,15 @@
   <requiredProperties>
     <requiredProperty key="pluginName"/>
 
-    <requiredProperty key="Implementation-Vendor"/>
-    <requiredProperty key="Implementation-Url"/>
-    <requiredProperty key="Gwt-Version"/>
+    <requiredProperty key="Implementation-Vendor">
+      <defaultValue>Gerrit Code Review</defaultValue>
+    </requiredProperty>
+    <requiredProperty key="Implementation-Url">
+      <defaultValue>http://code.google.com/p/gerrit/</defaultValue>
+    </requiredProperty>
+    <requiredProperty key="Gwt-Version">
+      <defaultValue>2.5.1</defaultValue>
+    </requiredProperty>
 
     <requiredProperty key="gerritApiVersion">
       <defaultValue>${defaultGerritApiVersion}</defaultValue>
@@ -49,6 +55,7 @@
       <directory></directory>
       <includes>
         <include>.gitignore</include>
+        <include>.settings/*</include>
         <include>LICENSE</include>
       </includes>
     </fileSet>
diff --git a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.core.resources.prefs b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..f15f85d
--- /dev/null
+++ b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,5 @@
+#Tue May 15 09:19:33 PDT 2012
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding//src/test/java=UTF-8
+encoding//src/test/resources=UTF-8
diff --git a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.core.runtime.prefs b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..8667cfd
--- /dev/null
+++ b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,3 @@
+#Tue Sep 02 16:59:24 PDT 2008
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.core.prefs b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..2f45466
--- /dev/null
+++ b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,264 @@
+#Fri Jul 16 23:39:13 PDT 2010
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.6
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=16
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=0
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=0
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=2
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=true
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=80
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=true
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=80
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=3
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=false
+org.eclipse.jdt.core.formatter.tabulation.char=space
+org.eclipse.jdt.core.formatter.tabulation.size=2
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
diff --git a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.ui.prefs b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..d4218a5
--- /dev/null
+++ b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,61 @@
+#Wed Jul 29 11:31:38 PDT 2009
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_Google Format
+formatter_settings_version=11
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=com.google;com;junit;net;org;java;javax;
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates/>
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=false
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=false
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=false
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_trailing_whitespaces=true
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
+sp_cleanup.remove_unnecessary_casts=false
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_blocks=false
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=false
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=false
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
diff --git a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/pom.xml b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/pom.xml
index 3a28c48..34912de 100644
--- a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/pom.xml
+++ b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/pom.xml
@@ -1,5 +1,5 @@
 <!--
-Copyright (C) 2012 The Android Open Source Project
+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.
@@ -71,7 +71,7 @@
         <artifactId>gwt-maven-plugin</artifactId>
         <version>${Gwt-Version}</version>
         <configuration>
-          <module>${package}.HelloPlugins</module>
+          <module>${package}.HelloPlugin</module>
           <disableClassMetadata>true</disableClassMetadata>
           <disableCastChecking>true</disableCastChecking>
           <webappDirectory>${project.build.directory}/classes/static</webappDirectory>
@@ -108,13 +108,6 @@
       <version>${Gwt-Version}</version>
       <scope>provided</scope>
     </dependency>
-
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <version>4.8.1</version>
-      <scope>test</scope>
-    </dependency>
   </dependencies>
 
   <repositories>
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
new file mode 100644
index 0000000..546381b
--- /dev/null
+++ b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/HelloMenu.java
@@ -0,0 +1,39 @@
+// 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 ${package};
+
+import com.google.gerrit.extensions.annotations.Listen;
+import com.google.gerrit.extensions.webui.TopMenu;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@Listen
+public class HelloMenu implements TopMenu {
+  public final static String MENU_ID = "hello_open-dialog-box";
+  private final List<MenuEntry> menuEntries;
+
+  public HelloMenu() {
+    menuEntries = new ArrayList<TopMenu.MenuEntry>();
+    menuEntries.add(new MenuEntry("Hello", Collections
+        .singletonList(new MenuItem("Open Dialog Box", "", "", MENU_ID))));
+  }
+
+  @Override
+  public List<MenuEntry> getEntries() {
+    return menuEntries;
+  }
+}
diff --git a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/HelloPlugins.gwt.xml b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/HelloPlugin.gwt.xml
similarity index 88%
rename from gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/HelloPlugins.gwt.xml
rename to gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/HelloPlugin.gwt.xml
index 4c70fcc..71a29d4 100644
--- a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/HelloPlugins.gwt.xml
+++ b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/HelloPlugin.gwt.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
- Copyright (C) 2012 The Android Open Source Project
+ 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.
@@ -14,7 +14,7 @@
  See the License for the specific language governing permissions and
  limitations under the License.
 -->
-<module rename-to="hello_gwt_plugins">
+<module rename-to="hello_gwt_plugin">
   <!-- Inherit the core Web Toolkit stuff.                        -->
   <inherits name="com.google.gwt.user.User"/>
   <!-- Other module inherits                                      -->
@@ -24,6 +24,6 @@
   <!-- resources to the plugin. No theme inherits lines were      -->
   <!-- added in order to make this plugin as simple as possible   -->
   <!-- Specify the app entry point class.                         -->
-  <entry-point class="${package}.client.HelloPlugins"/>
+  <entry-point class="${package}.client.HelloPlugin"/>
   <stylesheet src="hello.css"/>
 </module>
diff --git a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/MyExtension.java b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/MyExtension.java
index ebdbb26..cf0f52d 100644
--- a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/MyExtension.java
+++ b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/MyExtension.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Google
+// 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.
@@ -20,6 +20,6 @@
 @Listen
 public class MyExtension extends GwtPlugin {
   public MyExtension() {
-    super("hello_gwt_plugins");
+    super("hello_gwt_plugin");
   }
 }
diff --git a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/client/HelloPlugins.java b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/client/HelloPlugin.java
similarity index 70%
rename from gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/client/HelloPlugins.java
rename to gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/client/HelloPlugin.java
index 5584d85..24b8136 100644
--- a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/client/HelloPlugins.java
+++ b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/client/HelloPlugin.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Google Inc
+// 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.
@@ -14,33 +14,23 @@
 
 package ${package}.client;
 
-import com.google.gerrit.client.Plugin;
+import com.google.gerrit.plugin.client.Plugin;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.user.client.ui.Button;
 import com.google.gwt.user.client.ui.DialogBox;
-import com.google.gwt.user.client.ui.Image;
 import com.google.gwt.user.client.ui.RootPanel;
 import com.google.gwt.user.client.ui.VerticalPanel;
 
+import ${package}.HelloMenu;
+
 /**
- * HelloWorld Plugins.
+ * HelloWorld Plugin.
  */
-public class HelloPlugins extends Plugin {
+public class HelloPlugin extends Plugin {
 
   @Override
   public void onModuleLoad() {
-    Image img = new Image("http://code.google.com/webtoolkit/logo-185x175.png");
-    Button button = new Button("Click me");
-
-    VerticalPanel vPanel = new VerticalPanel();
-    vPanel.setWidth("100%");
-    vPanel.setHorizontalAlignment(VerticalPanel.ALIGN_CENTER);
-    vPanel.add(img);
-    vPanel.add(button);
-
-    RootPanel.get().add(vPanel);
-
     // Create the dialog box
     final DialogBox dialogBox = new DialogBox();
 
@@ -62,11 +52,14 @@
     // Set the contents of the Widget
     dialogBox.setWidget(dialogVPanel);
 
-    button.addClickHandler(new ClickHandler() {
-      public void onClick(ClickEvent event) {
-        dialogBox.center();
-        dialogBox.show();
-      }
-    });
+    RootPanel rootPanel = RootPanel.get(HelloMenu.MENU_ID);
+    rootPanel.getElement().removeAttribute("href");
+    rootPanel.addDomHandler(new ClickHandler() {
+        @Override
+        public void onClick(ClickEvent event) {
+          dialogBox.center();
+          dialogBox.show();
+        }
+    }, ClickEvent.getType());
   }
 }
diff --git a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/public/gwt-hello-gadgets-igoogle-thumb.png b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/public/gwt-hello-gadgets-igoogle-thumb.png
deleted file mode 100644
index e970774..0000000
--- a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/public/gwt-hello-gadgets-igoogle-thumb.png
+++ /dev/null
Binary files differ
diff --git a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/public/gwt-hello-gadgets-igoogle.png b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/public/gwt-hello-gadgets-igoogle.png
deleted file mode 100644
index c041149..0000000
--- a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/public/gwt-hello-gadgets-igoogle.png
+++ /dev/null
Binary files differ
diff --git a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/public/hello.css b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/public/hello.css
index 73bf5c6..13c5177 100644
--- a/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/public/hello.css
+++ b/gerrit-plugin-gwt-archetype/src/main/resources/archetype-resources/src/main/java/public/hello.css
@@ -101,3 +101,6 @@
   zoom: 1;
 }
 
+#hello_open-dialog-box {
+  cursor: pointer;
+}
diff --git a/gerrit-plugin-gwtui/BUCK b/gerrit-plugin-gwtui/BUCK
new file mode 100644
index 0000000..58eda5c
--- /dev/null
+++ b/gerrit-plugin-gwtui/BUCK
@@ -0,0 +1,20 @@
+SRC = 'src/main/java/com/google/gerrit/'
+
+gwt_module(
+  name = 'client',
+  srcs = glob([SRC + '**/*.java']),
+  gwtxml = SRC + 'Plugin.gwt.xml',
+  resources = glob(['src/main/resources/**/*']),
+  deps = [
+    '//lib/gwt:user',
+    '//lib/gwt:dev',
+  ],
+  visibility = ['PUBLIC'],
+)
+
+java_library(
+  name = 'src',
+  srcs = [],
+  resources = glob(['src/main/**/*']),
+  visibility = ['PUBLIC'],
+)
diff --git a/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/Plugin.gwt.xml b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/Plugin.gwt.xml
index 03edf67..1e2280a 100644
--- a/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/Plugin.gwt.xml
+++ b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/Plugin.gwt.xml
@@ -14,10 +14,10 @@
  limitations under the License.
 -->
 <module>
-  <define-linker name="gerrit_plugin" class="com.google.gerrit.linker.GerritPluginLinker"/>
+  <define-linker name="gerrit_plugin" class="com.google.gerrit.plugin.linker.GerritPluginLinker"/>
   <add-linker name="gerrit_plugin"/>
-  <generate-with class="com.google.gerrit.rebind.PluginGenerator">
-    <when-type-assignable class="com.google.gerrit.client.Plugin"/>
+  <generate-with class="com.google.gerrit.plugin.rebind.PluginGenerator">
+    <when-type-assignable class="com.google.gerrit.plugin.client.Plugin"/>
   </generate-with>
-  <source path="client"/>
+  <source path="plugin/client"/>
 </module>
diff --git a/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/client/Plugin.java b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/Plugin.java
similarity index 95%
rename from gerrit-plugin-gwtui/src/main/java/com/google/gerrit/client/Plugin.java
rename to gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/Plugin.java
index 1291b79..b5f7175 100644
--- a/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/client/Plugin.java
+++ b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/Plugin.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.client;
+package com.google.gerrit.plugin.client;
 
 import com.google.gwt.core.client.EntryPoint;
 
diff --git a/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/rpc/NativeString.java b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/rpc/NativeString.java
new file mode 100644
index 0000000..fe65857
--- /dev/null
+++ b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/rpc/NativeString.java
@@ -0,0 +1,54 @@
+// 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.plugin.client.rpc;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+/** Wraps a String that was returned from a JSON API. */
+public class NativeString extends JavaScriptObject {
+  private static final JavaScriptObject TYPE = init();
+
+  private static final native JavaScriptObject init()
+  /*-{ return $wnd.Gerrit.JsonString }-*/;
+
+  public final native String asString()
+  /*-{ return this.get(); }-*/;
+
+  public static final
+  AsyncCallback<NativeString> unwrap(final AsyncCallback<String> cb) {
+    return new AsyncCallback<NativeString>() {
+      @Override
+      public void onSuccess(NativeString result) {
+        cb.onSuccess(result != null ? result.asString() : null);
+      }
+
+      @Override
+      public void onFailure(Throwable caught) {
+        cb.onFailure(caught);
+      }
+    };
+  }
+
+  public static final boolean is(JavaScriptObject o) {
+    return is(TYPE, o);
+  }
+
+  private static final native boolean is(JavaScriptObject T, JavaScriptObject o)
+  /*-{ return o instanceof T }-*/;
+
+  protected NativeString() {
+  }
+}
diff --git a/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/rpc/Natives.java b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/rpc/Natives.java
new file mode 100644
index 0000000..6f5b136
--- /dev/null
+++ b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/rpc/Natives.java
@@ -0,0 +1,71 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.plugin.client.rpc;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArray;
+import com.google.gwt.json.client.JSONObject;
+
+import java.util.AbstractList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+public class Natives {
+  /**
+   * Get the names of defined properties on the object. The returned set
+   * iterates in the native iteration order, which may match the source order.
+   */
+  public static Set<String> keys(JavaScriptObject obj) {
+    if (obj != null) {
+      return new JSONObject(obj).keySet();
+    }
+    return Collections.emptySet();
+  }
+
+  public static <T extends JavaScriptObject> List<T> asList(
+      final JsArray<T> arr) {
+    if (arr == null) {
+      return null;
+    }
+    return new AbstractList<T>() {
+      @Override
+      public T set(int index, T element) {
+        T old = arr.get(index);
+        arr.set(index, element);
+        return old;
+      }
+
+      @Override
+      public T get(int index) {
+        return arr.get(index);
+      }
+
+      @Override
+      public int size() {
+        return arr.length();
+      }
+    };
+  }
+
+  public static <T extends JavaScriptObject> JsArray<T> arrayOf(T element) {
+    JsArray<T> arr = JavaScriptObject.createArray().cast();
+    arr.push(element);
+    return arr;
+  }
+
+  private Natives() {
+  }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/rpc/NoContent.java
similarity index 64%
copy from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
copy to gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/rpc/NoContent.java
index a5371d2..55744d5 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
+++ b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/rpc/NoContent.java
@@ -12,19 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.acceptance.rest.change;
+package com.google.gerrit.plugin.client.rpc;
 
-import com.google.common.collect.Maps;
+import com.google.gwt.core.client.JavaScriptObject;
 
-import java.util.Map;
-
-public class ReviewInput {
-  Map<String, Integer> labels;
-
-  public static ReviewInput approve() {
-    ReviewInput in = new ReviewInput();
-    in.labels = Maps.newHashMap();
-    in.labels.put("Code-Review", 2);
-    return in;
+public class NoContent extends JavaScriptObject {
+  protected NoContent() {
   }
 }
diff --git a/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/rpc/RestApi.java b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/rpc/RestApi.java
new file mode 100644
index 0000000..57a23e0
--- /dev/null
+++ b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/rpc/RestApi.java
@@ -0,0 +1,171 @@
+// 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.plugin.client.rpc;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.http.client.URL;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+public class RestApi {
+  private final StringBuilder path;
+  private boolean hasQueryParams;
+
+  public RestApi(String name) {
+    path = new StringBuilder();
+    path.append(name);
+  }
+
+  public RestApi view(String name) {
+    return idRaw(name);
+  }
+
+  public RestApi view(String pluginName, String name) {
+    return idRaw(pluginName + "~" + name);
+  }
+
+  public RestApi id(String id) {
+    return idRaw(URL.encodeQueryString(id));
+  }
+
+  public RestApi id(int id) {
+    return idRaw(Integer.toString(id));
+  }
+
+  public RestApi idRaw(String name) {
+    if (hasQueryParams) {
+      throw new IllegalStateException();
+    }
+    if (path.charAt(path.length() - 1) != '/') {
+      path.append('/');
+    }
+    path.append(name);
+    return this;
+  }
+
+  public RestApi addParameter(String name, String value) {
+    return addParameterRaw(name, URL.encodeQueryString(value));
+  }
+
+  public RestApi addParameter(String name, String... value) {
+    for (String val : value) {
+      addParameter(name, val);
+    }
+    return this;
+  }
+
+  public RestApi addParameterTrue(String name) {
+    return addParameterRaw(name, null);
+  }
+
+  public RestApi addParameter(String name, boolean value) {
+    return addParameterRaw(name, value ? "t" : "f");
+  }
+
+  public RestApi addParameter(String name, int value) {
+    return addParameterRaw(name, String.valueOf(value));
+  }
+
+  public RestApi addParameter(String name, Enum<?> value) {
+    return addParameterRaw(name, value.name());
+  }
+
+  public RestApi addParameterRaw(String name, String value) {
+    if (hasQueryParams) {
+      path.append("&");
+    } else {
+      path.append("?");
+      hasQueryParams = true;
+    }
+    path.append(name);
+    if (value != null) {
+      path.append("=").append(value);
+    }
+    return this;
+  }
+
+  public String path() {
+    return path.toString();
+  }
+
+  public <T extends JavaScriptObject>
+  void get(AsyncCallback<T> cb) {
+    get(path(), wrap(cb));
+  }
+
+  public void getString(AsyncCallback<String> cb) {
+    get(NativeString.unwrap(cb));
+  }
+
+  private native static void get(String p, JavaScriptObject r)
+  /*-{ $wnd.Gerrit.get(p, r) }-*/;
+
+  public <T extends JavaScriptObject>
+  void put(AsyncCallback<T> cb) {
+    put(path(), wrap(cb));
+  }
+
+  private native static void put(String p, JavaScriptObject r)
+  /*-{ $wnd.Gerrit.put(p, r) }-*/;
+
+  public <T extends JavaScriptObject>
+  void put(String content, AsyncCallback<T> cb) {
+    put(path(), content, wrap(cb));
+  }
+
+  private native static
+  void put(String p, String c, JavaScriptObject r)
+  /*-{ $wnd.Gerrit.put(p, c, r) }-*/;
+
+  public <T extends JavaScriptObject>
+  void put(JavaScriptObject content, AsyncCallback<T> cb) {
+    put(path(), content, wrap(cb));
+  }
+
+  private native static
+  void put(String p, JavaScriptObject c, JavaScriptObject r)
+  /*-{ $wnd.Gerrit.put(p, c, r) }-*/;
+
+  public <T extends JavaScriptObject>
+  void post(String content, AsyncCallback<T> cb) {
+    post(path(), content, wrap(cb));
+  }
+
+  private native static
+  void post(String p, String c, JavaScriptObject r)
+  /*-{ $wnd.Gerrit.post(p, c, r) }-*/;
+
+  public <T extends JavaScriptObject>
+  void post(JavaScriptObject content, AsyncCallback<T> cb) {
+    post(path(), content, wrap(cb));
+  }
+
+  private native static
+  void post(String p, JavaScriptObject c, JavaScriptObject r)
+  /*-{ $wnd.Gerrit.post(p, c, r) }-*/;
+
+  public void delete(AsyncCallback<NoContent> cb) {
+    delete(path(), wrap(cb));
+  }
+
+  private native static void delete(String p, JavaScriptObject r)
+  /*-{ '$wnd.Gerrit.delete'(p, r) }-*/;
+
+  private native static <T extends JavaScriptObject>
+  JavaScriptObject wrap(AsyncCallback<T> b) /*-{
+    return function(r) {
+      b.@com.google.gwt.user.client.rpc.AsyncCallback::onSuccess(Ljava/lang/Object;)(r)
+    }
+  }-*/;
+}
diff --git a/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/linker/GerritPluginLinker.java b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/linker/GerritPluginLinker.java
similarity index 96%
rename from gerrit-plugin-gwtui/src/main/java/com/google/gerrit/linker/GerritPluginLinker.java
rename to gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/linker/GerritPluginLinker.java
index e50334e..18f6e54 100644
--- a/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/linker/GerritPluginLinker.java
+++ b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/linker/GerritPluginLinker.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.linker;
+package com.google.gerrit.plugin.linker;
 
 import com.google.gwt.core.ext.LinkerContext;
 import com.google.gwt.core.linker.CrossSiteIframeLinker;
diff --git a/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/rebind/PluginGenerator.java b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/rebind/PluginGenerator.java
similarity index 98%
rename from gerrit-plugin-gwtui/src/main/java/com/google/gerrit/rebind/PluginGenerator.java
rename to gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/rebind/PluginGenerator.java
index 37c3e96..8278280 100644
--- a/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/rebind/PluginGenerator.java
+++ b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/rebind/PluginGenerator.java
@@ -13,7 +13,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.rebind;
+package com.google.gerrit.plugin.rebind;
 
 import java.io.PrintWriter;
 
diff --git a/gerrit-plugin-js-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml b/gerrit-plugin-js-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml
index 054caae..e4978dd 100644
--- a/gerrit-plugin-js-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml
+++ b/gerrit-plugin-js-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml
@@ -18,8 +18,12 @@
   <requiredProperties>
     <requiredProperty key="pluginName"/>
 
-    <requiredProperty key="Implementation-Vendor"/>
-    <requiredProperty key="Implementation-Url"/>
+    <requiredProperty key="Implementation-Vendor">
+      <defaultValue>Gerrit Code Review</defaultValue>
+    </requiredProperty>
+    <requiredProperty key="Implementation-Url">
+      <defaultValue>http://code.google.com/p/gerrit/</defaultValue>
+    </requiredProperty>
 
     <requiredProperty key="gerritApiType">
       <defaultValue>js</defaultValue>
@@ -55,6 +59,7 @@
       <directory></directory>
       <includes>
         <include>.gitignore</include>
+        <include>.settings/*</include>
         <include>LICENSE</include>
       </includes>
     </fileSet>
diff --git a/gerrit-plugin-js-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.core.resources.prefs b/gerrit-plugin-js-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..f15f85d
--- /dev/null
+++ b/gerrit-plugin-js-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,5 @@
+#Tue May 15 09:19:33 PDT 2012
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding//src/test/java=UTF-8
+encoding//src/test/resources=UTF-8
diff --git a/gerrit-plugin-js-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.core.runtime.prefs b/gerrit-plugin-js-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..8667cfd
--- /dev/null
+++ b/gerrit-plugin-js-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,3 @@
+#Tue Sep 02 16:59:24 PDT 2008
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/gerrit-plugin-js-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.core.prefs b/gerrit-plugin-js-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..2f45466
--- /dev/null
+++ b/gerrit-plugin-js-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,264 @@
+#Fri Jul 16 23:39:13 PDT 2010
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.6
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=16
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=0
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=0
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=2
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=true
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=80
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=true
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=80
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=3
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=false
+org.eclipse.jdt.core.formatter.tabulation.char=space
+org.eclipse.jdt.core.formatter.tabulation.size=2
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
diff --git a/gerrit-plugin-js-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.ui.prefs b/gerrit-plugin-js-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..d4218a5
--- /dev/null
+++ b/gerrit-plugin-js-archetype/src/main/resources/archetype-resources/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,61 @@
+#Wed Jul 29 11:31:38 PDT 2009
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_Google Format
+formatter_settings_version=11
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=com.google;com;junit;net;org;java;javax;
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates/>
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=false
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=false
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=false
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_trailing_whitespaces=true
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
+sp_cleanup.remove_unnecessary_casts=false
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_blocks=false
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=false
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=false
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
diff --git a/gerrit-plugin-js-archetype/src/main/resources/archetype-resources/pom.xml b/gerrit-plugin-js-archetype/src/main/resources/archetype-resources/pom.xml
index 85de7b5..207e49a 100644
--- a/gerrit-plugin-js-archetype/src/main/resources/archetype-resources/pom.xml
+++ b/gerrit-plugin-js-archetype/src/main/resources/archetype-resources/pom.xml
@@ -1,5 +1,5 @@
 <!--
-Copyright (C) 2012 The Android Open Source Project
+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.
diff --git a/gerrit-plugin-js-archetype/src/main/resources/archetype-resources/src/main/java/MyJsExtension.java b/gerrit-plugin-js-archetype/src/main/resources/archetype-resources/src/main/java/MyJsExtension.java
index bec914dd..da80a83 100644
--- a/gerrit-plugin-js-archetype/src/main/resources/archetype-resources/src/main/java/MyJsExtension.java
+++ b/gerrit-plugin-js-archetype/src/main/resources/archetype-resources/src/main/java/MyJsExtension.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2012 The Android Open Source Project
+// 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.
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Account.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Account.java
index 5cfa5e1..5dc2a08 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Account.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Account.java
@@ -56,7 +56,7 @@
  */
 public final class Account {
   public static enum FieldName {
-    FULL_NAME, USER_NAME, REGISTER_NEW_EMAIL;
+    FULL_NAME, USER_NAME, REGISTER_NEW_EMAIL
   }
 
   public static final String USER_NAME_PATTERN_FIRST = "[a-zA-Z]";
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGeneralPreferences.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGeneralPreferences.java
index 6cc83e5..efdc92b 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGeneralPreferences.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGeneralPreferences.java
@@ -27,12 +27,12 @@
 
   /** Preferred scheme type to download a change. */
   public static enum DownloadScheme {
-    ANON_GIT, ANON_HTTP, HTTP, SSH, REPO_DOWNLOAD, DEFAULT_DOWNLOADS;
+    ANON_GIT, ANON_HTTP, HTTP, SSH, REPO_DOWNLOAD, DEFAULT_DOWNLOADS
   }
 
   /** Preferred method to download a change. */
   public static enum DownloadCommand {
-    REPO_DOWNLOAD, PULL, CHECKOUT, CHERRY_PICK, FORMAT_PATCH, DEFAULT_DOWNLOADS;
+    REPO_DOWNLOAD, PULL, CHECKOUT, CHERRY_PICK, FORMAT_PATCH, DEFAULT_DOWNLOADS
   }
 
   public static enum DateFormat {
@@ -69,7 +69,7 @@
     COLLAPSE_ALL,
     EXPAND_MOST_RECENT,
     EXPAND_RECENT,
-    EXPAND_ALL;
+    EXPAND_ALL
   }
 
   public static enum DiffView {
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGroup.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGroup.java
index ea9c52d..a4846ac 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGroup.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGroup.java
@@ -142,7 +142,7 @@
      * who is a member of the owner group. These groups are not treated special
      * in the code.
      */
-    INTERNAL;
+    INTERNAL
   }
 
   /** Common UUID assigned to the "Project Owners" placeholder group. */
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AuthType.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AuthType.java
index b615fc5..6af9610 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AuthType.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AuthType.java
@@ -80,5 +80,5 @@
   CUSTOM_EXTENSION,
 
   /** Development mode to enable becoming anyone you want. */
-  DEVELOPMENT_BECOME_ANY_ACCOUNT;
+  DEVELOPMENT_BECOME_ANY_ACCOUNT
 }
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Project.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Project.java
index f3cf471..3b5a1aa 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Project.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Project.java
@@ -74,7 +74,7 @@
 
     MERGE_ALWAYS,
 
-    CHERRY_PICK;
+    CHERRY_PICK
   }
 
   public static enum State {
@@ -82,13 +82,13 @@
 
     READ_ONLY,
 
-    HIDDEN;
+    HIDDEN
   }
 
   public static enum InheritableBoolean {
     TRUE,
     FALSE,
-    INHERIT;
+    INHERIT
   }
 
   protected NameKey name;
diff --git a/gerrit-server/BUCK b/gerrit-server/BUCK
index 8119502..8b3f531 100644
--- a/gerrit-server/BUCK
+++ b/gerrit-server/BUCK
@@ -145,6 +145,7 @@
     '//gerrit-common:server',
     '//gerrit-extension-api:api',
     '//gerrit-reviewdb:server',
+    '//lib:args4j',
     '//lib:easymock',
     '//lib:guava',
     '//lib:gwtorm',
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 96a7b7e..1798f5a 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
@@ -582,6 +582,8 @@
 
       final List<String> args = new ArrayList<String>();
       addArg(args, "--change", event.change.id);
+      addArg(args, "--project", event.change.project);
+      addArg(args, "--branch", event.change.branch);
       addArg(args, "--changer", getDisplayName(account));
       addArg(args, "--old-topic", oldTopic);
       addArg(args, "--new-topic", event.change.topic);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/lifecycle/LifecycleModule.java b/gerrit-server/src/main/java/com/google/gerrit/lifecycle/LifecycleModule.java
index 04682f5..a22e6da 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/lifecycle/LifecycleModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/lifecycle/LifecycleModule.java
@@ -1,7 +1,7 @@
 package com.google.gerrit.lifecycle;
 
 import com.google.gerrit.extensions.events.LifecycleListener;
-import com.google.inject.AbstractModule;
+import com.google.gerrit.server.config.FactoryModule;
 import com.google.inject.Singleton;
 import com.google.inject.binder.LinkedBindingBuilder;
 import com.google.inject.internal.UniqueAnnotations;
@@ -9,7 +9,7 @@
 import java.lang.annotation.Annotation;
 
 /** Module to support registering a unique LifecyleListener. */
-public abstract class LifecycleModule extends AbstractModule {
+public abstract class LifecycleModule extends FactoryModule {
   /**
    * Create a unique listener binding.
    * <p>
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 a0196fd..4ab3442 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
@@ -64,7 +64,7 @@
   }
 
   public static enum Status {
-    NO_RULES, COMPILED;
+    NO_RULES, COMPILED
   }
 
   private final File ruleDir;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/AccessPath.java b/gerrit-server/src/main/java/com/google/gerrit/server/AccessPath.java
index 31df875..cb720c8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/AccessPath.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/AccessPath.java
@@ -32,5 +32,5 @@
   SSH_COMMAND,
 
   /** Access from a Git client using any Git protocol. */
-  GIT;
+  GIT
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/DefaultFileExtensionRegistry.java b/gerrit-server/src/main/java/com/google/gerrit/server/DefaultFileExtensionRegistry.java
new file mode 100644
index 0000000..15062ac
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/DefaultFileExtensionRegistry.java
@@ -0,0 +1,104 @@
+// 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;
+
+import com.google.common.collect.ImmutableMap;
+
+import eu.medsea.mimeutil.MimeType;
+import eu.medsea.mimeutil.MimeUtil;
+import eu.medsea.mimeutil.detector.MimeDetector;
+
+import java.io.File;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Collections;
+
+public class DefaultFileExtensionRegistry extends MimeDetector {
+  private static final MimeType INI = newMimeType("text/x-ini", 2);
+  private static final MimeType PYTHON = newMimeType("text/x-python", 2);
+
+  private static final ImmutableMap<String, MimeType> TYPES = ImmutableMap.of(
+      ".gitmodules", INI,
+      "project.config", INI,
+      "BUCK", PYTHON,
+      "defs", newMimeType(PYTHON.toString(), 1),
+      "go", newMimeType("text/x-go", 1));
+
+  private static MimeType newMimeType(String type, final int specificity) {
+    return new MimeType(type) {
+      private static final long serialVersionUID = 1L;
+
+      @Override
+      public int getSpecificity() {
+        return specificity;
+      }
+    };
+  }
+
+  static {
+    for (MimeType type : TYPES.values()) {
+      MimeUtil.addKnownMimeType(type);
+    }
+  }
+
+  @Override
+  public String getDescription() {
+    return getClass().getName();
+  }
+
+  @Override
+  protected Collection<MimeType> getMimeTypesFileName(String name) {
+    int s = name.lastIndexOf('/');
+    if (s >= 0) {
+      name = name.substring(s + 1);
+    }
+
+    MimeType type = TYPES.get(name);
+    if (type != null) {
+      return Collections.singletonList(type);
+    }
+
+    int d = name.lastIndexOf('.');
+    if (0 < d) {
+      type = TYPES.get(name.substring(d + 1));
+      if (type != null) {
+        return Collections.singletonList(type);
+      }
+    }
+
+    return Collections.emptyList();
+  }
+
+  @Override
+  protected Collection<MimeType> getMimeTypesFile(File file) {
+    return getMimeTypesFileName(file.getName());
+  }
+
+  @Override
+  protected Collection<MimeType> getMimeTypesURL(URL url) {
+    return getMimeTypesFileName(url.getPath());
+  }
+
+  @Override
+  protected Collection<MimeType> getMimeTypesInputStream(InputStream arg0) {
+    return Collections.emptyList();
+  }
+
+  @Override
+  protected Collection<MimeType> getMimeTypesByteArray(byte[] arg0) {
+    return Collections.emptyList();
+  }
+}
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 b271d6a..ff46b00 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
@@ -54,13 +54,13 @@
     if (HostPlatform.isWin32()) {
       register("eu.medsea.mimeutil.detector.WindowsRegistryMimeDetector");
     }
+    register(DefaultFileExtensionRegistry.class.getName());
   }
 
   private void register(String name) {
     mimeUtil.registerMimeDetector(name);
   }
 
-
   /**
    * Get specificity of mime types with generic types forced to low values
    *
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/StringUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/StringUtil.java
index fe1072d..2133dfb 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/StringUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/StringUtil.java
@@ -22,7 +22,7 @@
    * corresponds to its ASCII value, i.e. the string representation of
    * ASCII 0 is found in the first element of this array.
    */
-  static String[] NON_PRINTABLE_CHARS =
+  private static final String[] NON_PRINTABLE_CHARS =
     { "\\x00", "\\x01", "\\x02", "\\x03", "\\x04", "\\x05", "\\x06", "\\a",
       "\\b",   "\\t",   "\\n",   "\\v",   "\\f",   "\\r",   "\\x0e", "\\x0f",
       "\\x10", "\\x11", "\\x12", "\\x13", "\\x14", "\\x15", "\\x16", "\\x17",
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountDirectory.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountDirectory.java
index a4881a4..4dc9d79 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountDirectory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountDirectory.java
@@ -34,7 +34,7 @@
     AVATARS,
 
     /** Unique user identity to login to Gerrit, may be deprecated. */
-    USERNAME;
+    USERNAME
   }
 
   public abstract void fillAccountInfo(
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountResource.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountResource.java
index 629bd15..106c033 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountResource.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountResource.java
@@ -17,7 +17,9 @@
 import com.google.gerrit.extensions.restapi.RestResource;
 import com.google.gerrit.extensions.restapi.RestView;
 import com.google.gerrit.reviewdb.client.AccountSshKey;
+import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.change.ChangeResource;
 import com.google.inject.TypeLiteral;
 
 public class AccountResource implements RestResource {
@@ -33,6 +35,9 @@
   public static final TypeLiteral<RestView<SshKey>> SSH_KEY_KIND =
       new TypeLiteral<RestView<SshKey>>() {};
 
+  public static final TypeLiteral<RestView<StarredChange>> STARRED_CHANGE_KIND =
+      new TypeLiteral<RestView<StarredChange>>() {};
+
   private final IdentifiedUser user;
 
   public AccountResource(IdentifiedUser user) {
@@ -90,4 +95,17 @@
       return sshKey;
     }
   }
+
+  public static class StarredChange extends AccountResource {
+    private final ChangeResource change;
+
+    public StarredChange(IdentifiedUser user, ChangeResource change) {
+      super(user);
+      this.change = change;
+    }
+
+    public Change getChange() {
+      return change.getChange();
+    }
+  }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountVisibility.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountVisibility.java
index 7452da3..7ee8db6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountVisibility.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountVisibility.java
@@ -29,5 +29,5 @@
    * Other accounts are not visible to the given user unless they are explicitly
    * collaborating on a change.
    */
-  NONE;
+  NONE
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetActive.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetActive.java
index 76c7ddb..c042e18 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetActive.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetActive.java
@@ -14,16 +14,16 @@
 
 package com.google.gerrit.server.account;
 
-import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
+import com.google.gerrit.extensions.restapi.BinaryResult;
 import com.google.gerrit.extensions.restapi.Response;
 import com.google.gerrit.extensions.restapi.RestReadView;
 
 public class GetActive implements RestReadView<AccountResource> {
   @Override
-  public Object apply(AccountResource rsrc) throws ResourceNotFoundException {
+  public Object apply(AccountResource rsrc) {
     if (rsrc.getUser().getAccount().isActive()) {
-      return Response.ok("");
+      return BinaryResult.create("ok\n");
     }
-    throw new ResourceNotFoundException();
+    return Response.none();
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/Module.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/Module.java
index 79a0089..11f2e91 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/Module.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/Module.java
@@ -18,6 +18,7 @@
 import static com.google.gerrit.server.account.AccountResource.CAPABILITY_KIND;
 import static com.google.gerrit.server.account.AccountResource.EMAIL_KIND;
 import static com.google.gerrit.server.account.AccountResource.SSH_KEY_KIND;
+import static com.google.gerrit.server.account.AccountResource.STARRED_CHANGE_KIND;
 
 import com.google.gerrit.extensions.registration.DynamicMap;
 import com.google.gerrit.extensions.restapi.RestApiModule;
@@ -30,9 +31,10 @@
     bind(Capabilities.class);
 
     DynamicMap.mapOf(binder(), ACCOUNT_KIND);
+    DynamicMap.mapOf(binder(), CAPABILITY_KIND);
     DynamicMap.mapOf(binder(), EMAIL_KIND);
     DynamicMap.mapOf(binder(), SSH_KEY_KIND);
-    DynamicMap.mapOf(binder(), CAPABILITY_KIND);
+    DynamicMap.mapOf(binder(), STARRED_CHANGE_KIND);
 
     put(ACCOUNT_KIND).to(PutAccount.class);
     get(ACCOUNT_KIND).to(GetAccount.class);
@@ -65,6 +67,11 @@
     put(ACCOUNT_KIND, "preferences.diff").to(SetDiffPreferences.class);
     get(CAPABILITY_KIND).to(GetCapabilities.CheckOne.class);
 
+    child(ACCOUNT_KIND, "starred.changes").to(StarredChanges.class);
+    put(STARRED_CHANGE_KIND).to(StarredChanges.Put.class);
+    delete(STARRED_CHANGE_KIND).to(StarredChanges.Delete.class);
+    bind(StarredChanges.Create.class);
+
     install(new FactoryModuleBuilder().build(CreateAccount.Factory.class));
     install(new FactoryModuleBuilder().build(CreateEmail.Factory.class));
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/StarredChanges.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/StarredChanges.java
new file mode 100644
index 0000000..b560911
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/StarredChanges.java
@@ -0,0 +1,195 @@
+// 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.account;
+
+import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.restapi.AcceptsCreate;
+import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.BadRequestException;
+import com.google.gerrit.extensions.restapi.ChildCollection;
+import com.google.gerrit.extensions.restapi.IdString;
+import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
+import com.google.gerrit.extensions.restapi.Response;
+import com.google.gerrit.extensions.restapi.RestModifyView;
+import com.google.gerrit.extensions.restapi.RestReadView;
+import com.google.gerrit.extensions.restapi.RestView;
+import com.google.gerrit.extensions.restapi.TopLevelResource;
+import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
+import com.google.gerrit.reviewdb.client.StarredChange;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.change.ChangeResource;
+import com.google.gerrit.server.change.ChangesCollection;
+import com.google.gerrit.server.query.change.QueryChanges;
+import com.google.gwtorm.server.OrmDuplicateKeyException;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collections;
+
+class StarredChanges implements
+    ChildCollection<AccountResource, AccountResource.StarredChange>,
+    AcceptsCreate<AccountResource> {
+  private static final Logger log = LoggerFactory.getLogger(StarredChanges.class);
+
+  private final ChangesCollection changes;
+  private final DynamicMap<RestView<AccountResource.StarredChange>> views;
+  private final Provider<Create> createProvider;
+
+  @Inject
+  StarredChanges(ChangesCollection changes,
+      DynamicMap<RestView<AccountResource.StarredChange>> views,
+      Provider<Create> createProvider) {
+    this.changes = changes;
+    this.views = views;
+    this.createProvider = createProvider;
+  }
+
+  @Override
+  public AccountResource.StarredChange parse(AccountResource parent, IdString id)
+      throws ResourceNotFoundException, OrmException {
+    IdentifiedUser user = parent.getUser();
+    try {
+      user.asyncStarredChanges();
+
+      ChangeResource change = changes.parse(TopLevelResource.INSTANCE, id);
+      if (user.getStarredChanges().contains(change.getChange().getId())) {
+        return new AccountResource.StarredChange(user, change);
+      }
+      throw new ResourceNotFoundException(id);
+    } finally {
+      user.abortStarredChanges();
+    }
+  }
+
+  @Override
+  public DynamicMap<RestView<AccountResource.StarredChange>> views() {
+    return views;
+  }
+
+  @Override
+  public RestView<AccountResource> list() throws ResourceNotFoundException {
+    return new RestReadView<AccountResource>() {
+      @Override
+      public Object apply(AccountResource self) throws BadRequestException,
+          AuthException, OrmException {
+        QueryChanges query = changes.list();
+        query.addQuery("starredby:" + self.getUser().getAccountId().get());
+        return query.apply(TopLevelResource.INSTANCE);
+      }
+    };
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public RestModifyView<AccountResource, EmptyInput> create(
+      AccountResource parent, IdString id) throws UnprocessableEntityException{
+    try {
+      return createProvider.get()
+          .setChange(changes.parse(TopLevelResource.INSTANCE, id));
+    } catch (ResourceNotFoundException e) {
+      throw new UnprocessableEntityException(String.format("change %s not found", id.get()));
+    } catch (OrmException e) {
+      log.error("cannot resolve change", e);
+      throw new UnprocessableEntityException("internal server error");
+    }
+  }
+
+  static class Create implements RestModifyView<AccountResource, EmptyInput> {
+    private final Provider<CurrentUser> self;
+    private final Provider<ReviewDb> dbProvider;
+    private ChangeResource change;
+
+    @Inject
+    Create(Provider<CurrentUser> self, Provider<ReviewDb> dbProvider) {
+      this.self = self;
+      this.dbProvider = dbProvider;
+    }
+
+    Create setChange(ChangeResource change) {
+      this.change = change;
+      return this;
+    }
+
+    @Override
+    public Response<?> apply(AccountResource rsrc, EmptyInput in)
+        throws AuthException, OrmException {
+      if (self.get() != rsrc.getUser()) {
+        throw new AuthException("not allowed to add starred change");
+      }
+      try {
+        dbProvider.get().starredChanges().insert(Collections.singleton(
+            new StarredChange(new StarredChange.Key(
+                rsrc.getUser().getAccountId(),
+                change.getChange().getId()))));
+      } catch (OrmDuplicateKeyException e) {
+        return Response.none();
+      }
+      return Response.none();
+    }
+  }
+
+  static class Put implements
+      RestModifyView<AccountResource.StarredChange, EmptyInput> {
+    private final Provider<CurrentUser> self;
+
+    @Inject
+    Put(Provider<CurrentUser> self) {
+      this.self = self;
+    }
+
+    @Override
+    public Response<?> apply(AccountResource.StarredChange rsrc, EmptyInput in)
+        throws AuthException, OrmException {
+      if (self.get() != rsrc.getUser()) {
+        throw new AuthException("not allowed update starred changes");
+      }
+      return Response.none();
+    }
+  }
+
+  static class Delete implements
+      RestModifyView<AccountResource.StarredChange, EmptyInput> {
+    private final Provider<CurrentUser> self;
+    private final Provider<ReviewDb> dbProvider;
+
+    @Inject
+    Delete(Provider<CurrentUser> self, Provider<ReviewDb> dbProvider) {
+      this.self = self;
+      this.dbProvider = dbProvider;
+    }
+
+    @Override
+    public Response<?> apply(AccountResource.StarredChange rsrc,
+        EmptyInput in) throws AuthException, OrmException {
+      if (self.get() != rsrc.getUser()) {
+        throw new AuthException("not allowed remove starred change");
+      }
+      dbProvider.get().starredChanges().delete(Collections.singleton(
+          new StarredChange(new StarredChange.Key(
+              rsrc.getUser().getAccountId(),
+              rsrc.getChange().getId()))));
+      return Response.none();
+    }
+  }
+
+  static class EmptyInput {
+  }
+}
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
new file mode 100644
index 0000000..35700e6
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/GerritApiImpl.java
@@ -0,0 +1,34 @@
+// 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.api;
+
+import com.google.gerrit.extensions.api.GerritApi;
+import com.google.gerrit.extensions.api.changes.Changes;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+class GerritApiImpl implements GerritApi {
+  private final Provider<Changes> changes;
+
+  @Inject
+  GerritApiImpl(Provider<Changes> changes) {
+    this.changes = changes;
+  }
+
+  @Override
+  public Changes changes() {
+    return changes.get();
+  }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/Module.java
similarity index 64%
copy from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
copy to gerrit-server/src/main/java/com/google/gerrit/server/api/Module.java
index a5371d2..6f82a81 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/Module.java
@@ -12,19 +12,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.acceptance.rest.change;
+package com.google.gerrit.server.api;
 
-import com.google.common.collect.Maps;
+import com.google.gerrit.extensions.api.GerritApi;
+import com.google.inject.AbstractModule;
 
-import java.util.Map;
+public class Module extends AbstractModule {
+  @Override
+  protected void configure() {
+    bind(GerritApi.class).to(GerritApiImpl.class);
 
-public class ReviewInput {
-  Map<String, Integer> labels;
-
-  public static ReviewInput approve() {
-    ReviewInput in = new ReviewInput();
-    in.labels = Maps.newHashMap();
-    in.labels.put("Code-Review", 2);
-    return in;
+    install(new com.google.gerrit.server.api.changes.Module());
   }
 }
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
new file mode 100644
index 0000000..bbc147f
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
@@ -0,0 +1,145 @@
+// 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.api.changes;
+
+import com.google.gerrit.common.errors.EmailException;
+import com.google.gerrit.extensions.api.changes.AbandonInput;
+import com.google.gerrit.extensions.api.changes.ChangeApi;
+import com.google.gerrit.extensions.api.changes.Changes;
+import com.google.gerrit.extensions.api.changes.RestoreInput;
+import com.google.gerrit.extensions.api.changes.RevertInput;
+import com.google.gerrit.extensions.api.changes.RevisionApi;
+import com.google.gerrit.extensions.restapi.IdString;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.server.change.Abandon;
+import com.google.gerrit.server.change.ChangeResource;
+import com.google.gerrit.server.change.Restore;
+import com.google.gerrit.server.change.Revert;
+import com.google.gerrit.server.change.Revisions;
+import com.google.gerrit.server.project.NoSuchChangeException;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.assistedinject.Assisted;
+
+import java.io.IOException;
+
+class ChangeApiImpl implements ChangeApi {
+  interface Factory {
+    ChangeApiImpl create(ChangeResource change);
+  }
+
+  private final Changes changeApi;
+  private final Revisions revisions;
+  private final RevisionApiImpl.Factory revisionApi;
+  private final ChangeResource change;
+  private final Provider<Abandon> abandon;
+  private final Provider<Revert> revert;
+  private final Provider<Restore> restore;
+
+  @Inject
+  ChangeApiImpl(Changes changeApi,
+      Revisions revisions,
+      RevisionApiImpl.Factory revisionApi,
+      Provider<Abandon> abandon,
+      Provider<Revert> revert,
+      Provider<Restore> restore,
+      @Assisted ChangeResource change) {
+    this.changeApi = changeApi;
+    this.revert = revert;
+    this.revisions = revisions;
+    this.revisionApi = revisionApi;
+    this.abandon = abandon;
+    this.restore = restore;
+    this.change = change;
+  }
+
+  @Override
+  public String id() {
+    return Integer.toString(change.getChange().getId().get());
+  }
+
+  @Override
+  public RevisionApi current() throws RestApiException {
+    return revision("current");
+  }
+
+  @Override
+  public RevisionApi revision(int id) throws RestApiException {
+    return revision(String.valueOf(id));
+  }
+
+  @Override
+  public RevisionApi revision(String id) throws RestApiException {
+    try {
+      return revisionApi.create(
+          revisions.parse(change, IdString.fromDecoded(id)));
+    } catch (OrmException e) {
+      throw new RestApiException("Cannot parse revision", e);
+    }
+  }
+
+  @Override
+  public void abandon() throws RestApiException {
+    abandon(new AbandonInput());
+  }
+
+  @Override
+  public void abandon(AbandonInput in) throws RestApiException {
+    try {
+      abandon.get().apply(change, in);
+    } catch (OrmException e) {
+      throw new RestApiException("Cannot abandon change", e);
+    } catch (IOException e) {
+      throw new RestApiException("Cannot abandon change", e);
+    }
+  }
+
+  @Override
+  public void restore() throws RestApiException {
+    restore(new RestoreInput());
+  }
+
+  @Override
+  public void restore(RestoreInput in) throws RestApiException {
+    try {
+      restore.get().apply(change, in);
+    } catch (OrmException e) {
+      throw new RestApiException("Cannot restore change", e);
+    } catch (IOException e) {
+      throw new RestApiException("Cannot restore change", e);
+    }
+  }
+
+  @Override
+  public ChangeApi revert() throws RestApiException {
+    return revert(new RevertInput());
+  }
+
+  @Override
+  public ChangeApi revert(RevertInput in) throws RestApiException {
+    try {
+      return changeApi.id(revert.get().apply(change, in)._number);
+    } catch (OrmException e) {
+      throw new RestApiException("Cannot revert change", e);
+    } catch (EmailException e) {
+      throw new RestApiException("Cannot revert change", e);
+    } catch (IOException e) {
+      throw new RestApiException("Cannot revert change", e);
+    } catch (NoSuchChangeException e) {
+      throw new RestApiException("Cannot revert change", e);
+    }
+  }
+}
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
new file mode 100644
index 0000000..fdd0817
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangesImpl.java
@@ -0,0 +1,63 @@
+// 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.api.changes;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.gerrit.extensions.api.changes.ChangeApi;
+import com.google.gerrit.extensions.api.changes.Changes;
+import com.google.gerrit.extensions.restapi.IdString;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.extensions.restapi.TopLevelResource;
+import com.google.gerrit.extensions.restapi.Url;
+import com.google.gerrit.server.change.ChangesCollection;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+
+class ChangesImpl implements Changes {
+  private final ChangesCollection changes;
+  private final ChangeApiImpl.Factory api;
+
+  @Inject
+  ChangesImpl(ChangesCollection changes, ChangeApiImpl.Factory api) {
+    this.changes = changes;
+    this.api = api;
+  }
+
+  @Override
+  public ChangeApi id(int id) throws RestApiException {
+    return id(String.valueOf(id));
+  }
+
+  @Override
+  public ChangeApi id(String project, String branch, String id)
+      throws RestApiException {
+    return id(Joiner.on('~').join(ImmutableList.of(
+        Url.encode(project),
+        Url.encode(branch),
+        Url.encode(id))));
+  }
+
+  @Override
+  public ChangeApi id(String id) throws RestApiException {
+    try {
+      return api.create(changes.parse(
+          TopLevelResource.INSTANCE,
+          IdString.fromUrl(id)));
+    } catch (OrmException e) {
+      throw new RestApiException("Cannot parse change", e);
+    }
+  }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/Module.java
similarity index 61%
copy from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
copy to gerrit-server/src/main/java/com/google/gerrit/server/api/changes/Module.java
index a5371d2..dbf5f27 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ReviewInput.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/Module.java
@@ -12,19 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.acceptance.rest.change;
+package com.google.gerrit.server.api.changes;
 
-import com.google.common.collect.Maps;
+import com.google.gerrit.extensions.api.changes.Changes;
+import com.google.gerrit.server.config.FactoryModule;
 
-import java.util.Map;
+public class Module extends FactoryModule {
+  @Override
+  protected void configure() {
+    bind(Changes.class).to(ChangesImpl.class);
 
-public class ReviewInput {
-  Map<String, Integer> labels;
-
-  public static ReviewInput approve() {
-    ReviewInput in = new ReviewInput();
-    in.labels = Maps.newHashMap();
-    in.labels.put("Code-Review", 2);
-    return in;
+    factory(ChangeApiImpl.Factory.class);
+    factory(RevisionApiImpl.Factory.class);
   }
 }
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
new file mode 100644
index 0000000..4e401c0
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java
@@ -0,0 +1,108 @@
+// 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.api.changes;
+
+import com.google.gerrit.common.errors.EmailException;
+import com.google.gerrit.extensions.api.changes.ReviewInput;
+import com.google.gerrit.extensions.api.changes.RevisionApi;
+import com.google.gerrit.extensions.api.changes.SubmitInput;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.server.change.DeleteDraftPatchSet;
+import com.google.gerrit.server.change.PostReview;
+import com.google.gerrit.server.change.Rebase;
+import com.google.gerrit.server.change.RevisionResource;
+import com.google.gerrit.server.change.Submit;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.assistedinject.Assisted;
+
+import java.io.IOException;
+
+class RevisionApiImpl implements RevisionApi {
+  interface Factory {
+    RevisionApiImpl create(RevisionResource r);
+  }
+
+  private final Provider<DeleteDraftPatchSet> deleteDraft;
+  private final Provider<Rebase> rebase;
+  private final Provider<PostReview> review;
+  private final Provider<Submit> submit;
+  private final RevisionResource revision;
+
+  @Inject
+  RevisionApiImpl(Provider<DeleteDraftPatchSet> deleteDraft,
+      Provider<Rebase> rebase,
+      Provider<PostReview> review,
+      Provider<Submit> submit,
+      @Assisted RevisionResource r) {
+    this.deleteDraft = deleteDraft;
+    this.rebase = rebase;
+    this.review = review;
+    this.submit = submit;
+    this.revision = r;
+  }
+
+  @Override
+  public void review(ReviewInput in) throws RestApiException {
+    try {
+      review.get().apply(revision, in);
+    } catch (OrmException e) {
+      throw new RestApiException("Cannot post review", e);
+    } catch (IOException e) {
+      throw new RestApiException("Cannot post review", e);
+    }
+  }
+
+  @Override
+  public void submit() throws RestApiException {
+    SubmitInput in = new SubmitInput();
+    in.waitForMerge = true;
+    submit(in);
+  }
+
+  @Override
+  public void submit(SubmitInput in) throws RestApiException {
+    try {
+      submit.get().apply(revision, in);
+    } catch (OrmException e) {
+      throw new RestApiException("Cannot submit change", e);
+    } catch (IOException e) {
+      throw new RestApiException("Cannot submit change", e);
+    }
+  }
+
+  @Override
+  public void delete() throws RestApiException {
+    try {
+      deleteDraft.get().apply(revision, null);
+    } catch (OrmException e) {
+      throw new RestApiException("Cannot delete draft ps", e);
+    } catch (IOException e) {
+      throw new RestApiException("Cannot delete draft ps", e);
+    }
+  }
+
+  @Override
+  public void rebase() throws RestApiException {
+    try {
+      rebase.get().apply(revision, null);
+    } catch (OrmException e) {
+      throw new RestApiException("Cannot rebase ps", e);
+    } catch (EmailException e) {
+      throw new RestApiException("Cannot rebase ps", e);
+    }
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Abandon.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Abandon.java
index 4959cfb..1218de8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Abandon.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Abandon.java
@@ -17,9 +17,9 @@
 import com.google.common.base.Strings;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.gerrit.common.ChangeHooks;
+import com.google.gerrit.extensions.api.changes.AbandonInput;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.BadRequestException;
-import com.google.gerrit.extensions.restapi.DefaultInput;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.extensions.webui.UiAction;
@@ -29,7 +29,6 @@
 import com.google.gerrit.server.ApprovalsUtil;
 import com.google.gerrit.server.ChangeUtil;
 import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.change.Abandon.Input;
 import com.google.gerrit.server.change.ChangeJson.ChangeInfo;
 import com.google.gerrit.server.index.ChangeIndexer;
 import com.google.gerrit.server.mail.AbandonedSender;
@@ -46,7 +45,7 @@
 import java.io.IOException;
 import java.util.Collections;
 
-public class Abandon implements RestModifyView<ChangeResource, Input>,
+public class Abandon implements RestModifyView<ChangeResource, AbandonInput>,
     UiAction<ChangeResource> {
   private static final Logger log = LoggerFactory.getLogger(Abandon.class);
 
@@ -56,11 +55,6 @@
   private final ChangeJson json;
   private final ChangeIndexer indexer;
 
-  public static class Input {
-    @DefaultInput
-    public String message;
-  }
-
   @Inject
   Abandon(ChangeHooks hooks,
       AbandonedSender.Factory abandonedSenderFactory,
@@ -75,9 +69,9 @@
   }
 
   @Override
-  public Object apply(ChangeResource req, Input input)
+  public Object apply(ChangeResource req, AbandonInput input)
       throws BadRequestException, AuthException,
-      ResourceConflictException, Exception {
+      ResourceConflictException, OrmException, IOException {
     ChangeControl control = req.getControl();
     IdentifiedUser caller = (IdentifiedUser) control.getCurrentUser();
     Change change = req.getChange();
@@ -144,7 +138,7 @@
           && resource.getControl().canAbandon());
   }
 
-  private ChangeMessage newMessage(Input input, IdentifiedUser caller,
+  private ChangeMessage newMessage(AbandonInput input, IdentifiedUser caller,
       Change change) throws OrmException {
     StringBuilder msg = new StringBuilder();
     msg.append("Abandoned");
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 f64e424..87229b3 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
@@ -31,6 +31,9 @@
 
 import com.google.common.base.Joiner;
 import com.google.common.base.Objects;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
 import com.google.common.collect.HashBasedTable;
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.ImmutableList;
@@ -64,6 +67,7 @@
 import com.google.gerrit.reviewdb.client.PatchSetApproval;
 import com.google.gerrit.reviewdb.client.PatchSetInfo;
 import com.google.gerrit.reviewdb.client.PatchSetInfo.ParentInfo;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.client.UserIdentity;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.AnonymousUser;
@@ -77,7 +81,8 @@
 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;
 import com.google.gwtorm.server.OrmException;
 import com.google.gwtorm.server.ResultSet;
@@ -87,6 +92,7 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.IOException;
 import java.sql.Timestamp;
 import java.util.Collection;
 import java.util.Collections;
@@ -97,6 +103,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
+import java.util.concurrent.ExecutionException;
 
 public class ChangeJson {
   private static final Logger log = LoggerFactory.getLogger(ChangeJson.class);
@@ -122,7 +129,7 @@
   private final Provider<CurrentUser> userProvider;
   private final AnonymousUser anonymous;
   private final IdentifiedUser.GenericFactory userFactory;
-  private final ChangeControl.GenericFactory changeControlGenericFactory;
+  private final ProjectControl.GenericFactory projectControlFactory;
   private final PatchSetInfoFactory patchSetInfoFactory;
   private final FileInfoJson fileInfoJson;
   private final AccountInfo.Loader.Factory accountLoaderFactory;
@@ -131,20 +138,20 @@
   private final DynamicMap<RestView<ChangeResource>> changes;
   private final Revisions revisions;
 
-  private ChangeControl.Factory changeControlUserFactory;
   private EnumSet<ListChangesOption> options;
   private AccountInfo.Loader accountLoader;
   private ChangeControl lastControl;
   private Set<Change.Id> reviewed;
+  private LoadingCache<Project.NameKey, ProjectControl> projectControls;
 
   @Inject
   ChangeJson(
       Provider<ReviewDb> db,
       LabelNormalizer ln,
-      Provider<CurrentUser> userProvider,
+      Provider<CurrentUser> user,
       AnonymousUser au,
       IdentifiedUser.GenericFactory uf,
-      ChangeControl.GenericFactory ccf,
+      ProjectControl.GenericFactory pcf,
       PatchSetInfoFactory psi,
       FileInfoJson fileInfoJson,
       AccountInfo.Loader.Factory ailf,
@@ -154,10 +161,10 @@
       Revisions revisions) {
     this.db = db;
     this.labelNormalizer = ln;
-    this.userProvider = userProvider;
+    this.userProvider = user;
     this.anonymous = au;
     this.userFactory = uf;
-    this.changeControlGenericFactory = ccf;
+    this.projectControlFactory = pcf;
     this.patchSetInfoFactory = psi;
     this.fileInfoJson = fileInfoJson;
     this.accountLoaderFactory = ailf;
@@ -167,6 +174,15 @@
     this.revisions = revisions;
 
     options = EnumSet.noneOf(ListChangesOption.class);
+    projectControls = CacheBuilder.newBuilder()
+      .concurrencyLevel(1)
+      .build(new CacheLoader<Project.NameKey, ProjectControl>() {
+        @Override
+        public ProjectControl load(Project.NameKey key)
+            throws NoSuchProjectException, IOException {
+          return projectControlFactory.controlFor(key, userProvider.get());
+        }
+      });
   }
 
   public ChangeJson addOption(ListChangesOption o) {
@@ -179,11 +195,6 @@
     return this;
   }
 
-  public ChangeJson setChangeControlFactory(ChangeControl.Factory cf) {
-    changeControlUserFactory = cf;
-    return this;
-  }
-
   public ChangeInfo format(ChangeResource rsrc) throws OrmException {
     return format(new ChangeData(rsrc.getControl()));
   }
@@ -321,13 +332,12 @@
     }
 
     try {
-      if (changeControlUserFactory != null) {
-        ctrl = changeControlUserFactory.controlFor(cd.change(db));
-      } else {
-        ctrl = changeControlGenericFactory.controlFor(cd.change(db),
-            userProvider.get());
+      Change change = cd.change(db);
+      if (change == null) {
+        return null;
       }
-    } catch (NoSuchChangeException e) {
+      ctrl = projectControls.get(change.getProject()).controlFor(change);
+    } catch (ExecutionException e) {
       return null;
     }
     lastControl = ctrl;
@@ -551,10 +561,10 @@
           Maps.newHashMapWithExpectedSize(labels.size());
 
       if (detailed) {
-        for (String name : labels.keySet()) {
+        for (Map.Entry<String, LabelInfo> entry : labels.entrySet()) {
           ApprovalInfo ai = approvalInfo(accountId, 0, null);
-          byLabel.put(name, ai);
-          labels.get(name).addApproval(ai);
+          byLabel.put(entry.getKey(), ai);
+          entry.getValue().addApproval(ai);
         }
       }
       for (PatchSetApproval psa : current.get(accountId)) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeResource.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeResource.java
index 87910bf..b0562a9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeResource.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeResource.java
@@ -57,6 +57,7 @@
     Hasher h = Hashing.md5().newHasher()
       .putLong(getChange().getLastUpdatedOn().getTime())
       .putInt(getChange().getRowVersion())
+      .putBoolean(user.getStarredChanges().contains(getChange().getId()))
       .putInt(user.isIdentifiedUser()
           ? ((IdentifiedUser) user).getAccountId().get()
           : 0);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangesCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangesCollection.java
index 45328b1..b7d8819 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangesCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangesCollection.java
@@ -23,6 +23,7 @@
 import com.google.gerrit.extensions.restapi.TopLevelResource;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.query.change.QueryChanges;
@@ -30,31 +31,33 @@
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
-import java.io.UnsupportedEncodingException;
 import java.util.Collections;
 import java.util.List;
 
 public class ChangesCollection implements
     RestCollection<TopLevelResource, ChangeResource> {
   private final Provider<ReviewDb> db;
-  private final ChangeControl.Factory changeControlFactory;
+  private final Provider<CurrentUser> user;
+  private final ChangeControl.GenericFactory changeControlFactory;
   private final Provider<QueryChanges> queryFactory;
   private final DynamicMap<RestView<ChangeResource>> views;
 
   @Inject
   ChangesCollection(
       Provider<ReviewDb> dbProvider,
-      ChangeControl.Factory changeControlFactory,
+      Provider<CurrentUser> user,
+      ChangeControl.GenericFactory changeControlFactory,
       Provider<QueryChanges> queryFactory,
       DynamicMap<RestView<ChangeResource>> views) {
     this.db = dbProvider;
+    this.user = user;
     this.changeControlFactory = changeControlFactory;
     this.queryFactory = queryFactory;
     this.views = views;
   }
 
   @Override
-  public RestView<TopLevelResource> list() {
+  public QueryChanges list() {
     return queryFactory.get();
   }
 
@@ -65,8 +68,7 @@
 
   @Override
   public ChangeResource parse(TopLevelResource root, IdString id)
-      throws ResourceNotFoundException, OrmException,
-      UnsupportedEncodingException {
+      throws ResourceNotFoundException, OrmException {
     List<Change> changes = findChanges(id.encoded());
     if (changes.size() != 1) {
       throw new ResourceNotFoundException(id);
@@ -74,7 +76,7 @@
 
     ChangeControl control;
     try {
-      control = changeControlFactory.validateFor(changes.get(0));
+      control = changeControlFactory.validateFor(changes.get(0), user.get());
     } catch (NoSuchChangeException e) {
       throw new ResourceNotFoundException(id);
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/EmailReviewComments.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/EmailReviewComments.java
index 11a9edd..c8ff2f0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/EmailReviewComments.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/EmailReviewComments.java
@@ -15,6 +15,7 @@
 package com.google.gerrit.server.change;
 
 import com.google.common.collect.Lists;
+import com.google.gerrit.extensions.api.changes.ReviewInput.NotifyHandling;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.ChangeMessage;
@@ -22,7 +23,6 @@
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
-import com.google.gerrit.server.change.PostReview.NotifyHandling;
 import com.google.gerrit.server.git.WorkQueue;
 import com.google.gerrit.server.mail.CommentSender;
 import com.google.gerrit.server.patch.PatchSetInfoFactory;
@@ -61,7 +61,7 @@
   private final SchemaFactory<ReviewDb> schemaFactory;
   private final ThreadLocalRequestContext requestContext;
 
-  private final PostReview.NotifyHandling notify;
+  private final NotifyHandling notify;
   private final Change change;
   private final PatchSet patchSet;
   private final Account.Id authorId;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Files.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Files.java
index ec8234f..98e2ee9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Files.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Files.java
@@ -37,7 +37,6 @@
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.patch.PatchList;
 import com.google.gerrit.server.patch.PatchListCache;
-import com.google.gerrit.server.patch.PatchListEntry;
 import com.google.gerrit.server.patch.PatchListNotAvailableException;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
@@ -45,9 +44,9 @@
 
 import org.eclipse.jgit.lib.ObjectReader;
 import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.revwalk.RevTree;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
 import org.kohsuke.args4j.Option;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -219,23 +218,49 @@
           List<String> pathList = Lists.newArrayListWithCapacity(sz);
 
           RevWalk rw = new RevWalk(reader);
-          RevTree o = rw.parseCommit(oldList.getNewId()).getTree();
-          RevTree c = rw.parseCommit(curList.getNewId()).getTree();
-          for (PatchListEntry p : curList.getPatches()) {
-            String path = p.getNewName();
-            if (!Patch.COMMIT_MSG.equals(path) && paths.contains(path)) {
-              TreeWalk tw = TreeWalk.forPath(reader, path, o, c);
-              if (tw != null
-                  && tw.getRawMode(0) != 0
-                  && tw.getRawMode(1) != 0
-                  && tw.idEqual(0, 1)) {
-                inserts.add(new AccountPatchReview(
-                    new Patch.Key(
-                        resource.getPatchSet().getId(),
-                        path),
-                      userId));
-                pathList.add(path);
-              }
+          TreeWalk tw = new TreeWalk(reader);
+          tw.setFilter(PathFilterGroup.createFromStrings(paths));
+          tw.setRecursive(true);
+          int o = tw.addTree(rw.parseCommit(oldList.getNewId()).getTree());
+          int c = tw.addTree(rw.parseCommit(curList.getNewId()).getTree());
+
+          int op = -1;
+          if (oldList.getOldId() != null) {
+            op = tw.addTree(rw.parseCommit(oldList.getOldId()).getTree());
+          }
+
+          int cp = -1;
+          if (curList.getOldId() != null) {
+            cp = tw.addTree(rw.parseCommit(curList.getOldId()).getTree());
+          }
+
+          while (tw.next()) {
+            String path = tw.getPathString();
+            if (tw.getRawMode(o) != 0 && tw.getRawMode(c) != 0
+                && tw.idEqual(o, c)
+                && paths.contains(path)) {
+              // File exists in previously reviewed oldList and in curList.
+              // File content is identical.
+              inserts.add(new AccountPatchReview(
+                  new Patch.Key(
+                      resource.getPatchSet().getId(),
+                      path),
+                    userId));
+              pathList.add(path);
+            } else if (op >= 0 && cp >= 0
+                && tw.getRawMode(o) == 0 && tw.getRawMode(c) == 0
+                && tw.getRawMode(op) != 0 && tw.getRawMode(cp) != 0
+                && tw.idEqual(op, cp)
+                && paths.contains(path)) {
+              // File was deleted in previously reviewed oldList and curList.
+              // File exists in ancestor of oldList and curList.
+              // File content is identical in ancestors.
+              inserts.add(new AccountPatchReview(
+                  new Patch.Key(
+                      resource.getPatchSet().getId(),
+                      path),
+                    userId));
+              pathList.add(path);
             }
           }
           db.get().accountPatchReviews().insert(inserts);
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 753a70b..43504fa 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
@@ -193,7 +193,7 @@
   enum IntraLineStatus {
     OK,
     TIMEOUT,
-    FAILURE;
+    FAILURE
   }
 
   private static class Content {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java
index 7fb09b5..9ed2bee 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java
@@ -31,6 +31,7 @@
 public class Module extends RestApiModule {
   @Override
   protected void configure() {
+    bind(ChangesCollection.class);
     bind(Revisions.class);
     bind(Reviewers.class);
     bind(Drafts.class);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java
index e4f4f1f..f604e0b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java
@@ -82,11 +82,11 @@
    * validation.
    */
   public static enum ValidatePolicy {
-    GERRIT, RECEIVE_COMMITS, NONE;
+    GERRIT, RECEIVE_COMMITS, NONE
   }
 
   public static enum ChangeKind {
-    REWORK, TRIVIAL_REBASE, NO_CODE_CHANGE;
+    REWORK, TRIVIAL_REBASE, NO_CODE_CHANGE
   }
 
   private final ChangeHooks hooks;
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 367087c..8e9e494 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
@@ -23,14 +23,17 @@
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.Futures;
 import com.google.gerrit.common.ChangeHooks;
-import com.google.gerrit.common.changes.Side;
 import com.google.gerrit.common.data.LabelType;
 import com.google.gerrit.common.data.LabelTypes;
 import com.google.gerrit.common.data.Permission;
 import com.google.gerrit.common.data.PermissionRange;
+import com.google.gerrit.extensions.api.changes.ReviewInput;
+import com.google.gerrit.extensions.api.changes.ReviewInput.Comment;
+import com.google.gerrit.extensions.api.changes.ReviewInput.DraftHandling;
+import com.google.gerrit.extensions.api.changes.ReviewInput.NotifyHandling;
+import com.google.gerrit.extensions.api.changes.ReviewInput.Side;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.BadRequestException;
-import com.google.gerrit.extensions.restapi.DefaultInput;
 import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
 import com.google.gerrit.extensions.restapi.Url;
@@ -44,7 +47,6 @@
 import com.google.gerrit.server.ChangeUtil;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.AccountsCollection;
-import com.google.gerrit.server.change.PostReview.Input;
 import com.google.gerrit.server.index.ChangeIndexer;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.util.TimeUtil;
@@ -62,65 +64,9 @@
 import java.util.List;
 import java.util.Map;
 
-public class PostReview implements RestModifyView<RevisionResource, Input> {
+public class PostReview implements RestModifyView<RevisionResource, ReviewInput> {
   private static final Logger log = LoggerFactory.getLogger(PostReview.class);
 
-  public static class Input {
-    @DefaultInput
-    public String message;
-
-    public Map<String, Short> labels;
-    public Map<String, List<Comment>> comments;
-
-    /**
-     * If true require all labels to be within the user's permitted ranges based
-     * on access controls, attempting to use a label not granted to the user
-     * will fail the entire modify operation early. If false the operation will
-     * execute anyway, but the proposed labels given by the user will be
-     * modified to be the "best" value allowed by the access controls, or
-     * ignored if the label does not exist.
-     */
-    public boolean strictLabels = true;
-
-    /**
-     * How to process draft comments already in the database that were not also
-     * described in this input request.
-     */
-    public DraftHandling drafts = DraftHandling.DELETE;
-
-    /** Who to send email notifications to after review is stored. */
-    public NotifyHandling notify = NotifyHandling.ALL;
-
-    /**
-     * Account ID, name, email address or username of another user. The review
-     * will be posted/updated on behalf of this named user instead of the
-     * caller. Caller must have the labelAs-$NAME permission granted for each
-     * label that appears in {@link #labels}. This is in addition to the named
-     * user also needing to have permission to use the labels.
-     * <p>
-     * {@link #strictLabels} impacts how labels is processed for the named user,
-     * not the caller.
-     */
-    public String onBehalfOf;
-  }
-
-  public static enum DraftHandling {
-    DELETE, PUBLISH, KEEP;
-  }
-
-  public static enum NotifyHandling {
-    NONE, OWNER, OWNER_REVIEWERS, ALL;
-  }
-
-  public static class Comment {
-    public String id;
-    public Side side;
-    public int line;
-    public String inReplyTo;
-    public String message;
-    public CommentRange range;
-  }
-
   static class Output {
     Map<String, Short> labels;
   }
@@ -152,7 +98,7 @@
   }
 
   @Override
-  public Object apply(RevisionResource revision, Input input)
+  public Object apply(RevisionResource revision, ReviewInput input)
       throws AuthException, BadRequestException, OrmException,
       UnprocessableEntityException, IOException {
     if (input.onBehalfOf != null) {
@@ -210,7 +156,7 @@
     return output;
   }
 
-  private RevisionResource onBehalfOf(RevisionResource rev, Input in)
+  private RevisionResource onBehalfOf(RevisionResource rev, ReviewInput in)
       throws BadRequestException, AuthException, UnprocessableEntityException,
       OrmException {
     if (in.labels == null || in.labels.isEmpty()) {
@@ -370,7 +316,13 @@
         e.setWrittenOn(timestamp);
         e.setSide(c.side == Side.PARENT ? (short) 0 : (short) 1);
         e.setMessage(c.message);
-        e.setRange(c.range);
+        if (c.range != null) {
+          e.setRange(new CommentRange(
+              c.range.startLine,
+              c.range.startCharacter,
+              c.range.endLine,
+              c.range.endCharacter));
+        }
         (create ? ins : upd).add(e);
       }
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Restore.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Restore.java
index d31d1f0..a055993 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Restore.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Restore.java
@@ -17,8 +17,8 @@
 import com.google.common.base.Strings;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.gerrit.common.ChangeHooks;
+import com.google.gerrit.extensions.api.changes.RestoreInput;
 import com.google.gerrit.extensions.restapi.AuthException;
-import com.google.gerrit.extensions.restapi.DefaultInput;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.extensions.webui.UiAction;
@@ -30,7 +30,6 @@
 import com.google.gerrit.server.ChangeUtil;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.change.ChangeJson.ChangeInfo;
-import com.google.gerrit.server.change.Restore.Input;
 import com.google.gerrit.server.index.ChangeIndexer;
 import com.google.gerrit.server.mail.ReplyToChangeSender;
 import com.google.gerrit.server.mail.RestoredSender;
@@ -46,7 +45,7 @@
 import java.io.IOException;
 import java.util.Collections;
 
-public class Restore implements RestModifyView<ChangeResource, Input>,
+public class Restore implements RestModifyView<ChangeResource, RestoreInput>,
     UiAction<ChangeResource> {
   private static final Logger log = LoggerFactory.getLogger(Restore.class);
 
@@ -56,11 +55,6 @@
   private final ChangeJson json;
   private final ChangeIndexer indexer;
 
-  public static class Input {
-    @DefaultInput
-    public String message;
-  }
-
   @Inject
   Restore(ChangeHooks hooks,
       RestoredSender.Factory restoredSenderFactory,
@@ -75,8 +69,9 @@
   }
 
   @Override
-  public Object apply(ChangeResource req, Input input)
-      throws Exception {
+  public Object apply(ChangeResource req, RestoreInput input)
+      throws OrmException, IOException, AuthException,
+      ResourceConflictException {
     ChangeControl control = req.getControl();
     IdentifiedUser caller = (IdentifiedUser) control.getCurrentUser();
     Change change = req.getChange();
@@ -143,7 +138,7 @@
           && resource.getControl().canRestore());
   }
 
-  private ChangeMessage newMessage(Input input, IdentifiedUser caller,
+  private ChangeMessage newMessage(RestoreInput input, IdentifiedUser caller,
       Change change) throws OrmException {
     StringBuilder msg = new StringBuilder();
     msg.append("Restored");
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Revert.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Revert.java
index 73a6b03..74bc68f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Revert.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Revert.java
@@ -16,6 +16,8 @@
 
 import com.google.common.base.Strings;
 import com.google.gerrit.common.ChangeHooks;
+import com.google.gerrit.common.errors.EmailException;
+import com.google.gerrit.extensions.api.changes.RevertInput;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.BadRequestException;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
@@ -27,21 +29,25 @@
 import com.google.gerrit.server.ChangeUtil;
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.change.Revert.Input;
+import com.google.gerrit.server.change.ChangeJson.ChangeInfo;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.validators.CommitValidators;
 import com.google.gerrit.server.mail.RevertedSender;
 import com.google.gerrit.server.patch.PatchSetInfoFactory;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.InvalidChangeOperationException;
+import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.ssh.NoSshInfo;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
 import org.eclipse.jgit.lib.PersonIdent;
 import org.eclipse.jgit.lib.Repository;
 
-public class Revert implements RestModifyView<ChangeResource, Input>,
+import java.io.IOException;
+
+public class Revert implements RestModifyView<ChangeResource, RevertInput>,
     UiAction<ChangeResource> {
   private final ChangeHooks hooks;
   private final RevertedSender.Factory revertedSenderFactory;
@@ -53,10 +59,6 @@
   private final PatchSetInfoFactory patchSetInfoFactory;
   private final ChangeInserter.Factory changeInserterFactory;
 
-  public static class Input {
-    public String message;
-  }
-
   @Inject
   Revert(ChangeHooks hooks,
       RevertedSender.Factory revertedSenderFactory,
@@ -79,7 +81,9 @@
   }
 
   @Override
-  public Object apply(ChangeResource req, Input input) throws Exception {
+  public ChangeInfo apply(ChangeResource req, RevertInput input)
+      throws AuthException, ResourceConflictException, IOException,
+      NoSuchChangeException, EmailException, OrmException, BadRequestException {
     ChangeControl control = req.getControl();
     Change change = req.getChange();
     if (!control.canAddPatchSet()) {
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 a507096..2dc066c 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
@@ -21,6 +21,7 @@
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.gerrit.common.data.SubmitRecord;
+import com.google.gerrit.extensions.api.changes.SubmitInput;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.extensions.restapi.RestModifyView;
@@ -34,7 +35,6 @@
 import com.google.gerrit.server.ChangeUtil;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.ProjectUtil;
-import com.google.gerrit.server.change.Submit.Input;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.MergeQueue;
 import com.google.gerrit.server.index.ChangeIndexer;
@@ -53,14 +53,14 @@
 import java.util.Collections;
 import java.util.List;
 
-public class Submit implements RestModifyView<RevisionResource, Input>,
+public class Submit implements RestModifyView<RevisionResource, SubmitInput>,
     UiAction<RevisionResource> {
   public static class Input {
     public boolean waitForMerge;
   }
 
   public enum Status {
-    SUBMITTED, MERGED;
+    SUBMITTED, MERGED
   }
 
   public static class Output {
@@ -90,9 +90,9 @@
   }
 
   @Override
-  public Output apply(RevisionResource rsrc, Input input) throws AuthException,
-      ResourceConflictException, RepositoryNotFoundException, IOException,
-      OrmException {
+  public Output apply(RevisionResource rsrc, SubmitInput input)
+      throws AuthException, ResourceConflictException,
+      RepositoryNotFoundException, IOException, OrmException {
     ChangeControl control = rsrc.getControl();
     IdentifiedUser caller = (IdentifiedUser) control.getCurrentUser();
     Change change = rsrc.getChange();
@@ -317,7 +317,7 @@
   }
 
   public static class CurrentRevision implements
-      RestModifyView<ChangeResource, Input> {
+      RestModifyView<ChangeResource, SubmitInput> {
     private final Provider<ReviewDb> dbProvider;
     private final Submit submit;
     private final ChangeJson json;
@@ -332,9 +332,9 @@
     }
 
     @Override
-    public Object apply(ChangeResource rsrc, Input input) throws AuthException,
-        ResourceConflictException, RepositoryNotFoundException, IOException,
-        OrmException {
+    public Object apply(ChangeResource rsrc, SubmitInput input)
+        throws AuthException, ResourceConflictException,
+        RepositoryNotFoundException, IOException, OrmException {
       PatchSet ps = dbProvider.get().patchSets()
         .get(rsrc.getChange().currentPatchSetId());
       if (ps == null) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/TestSubmitRule.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/TestSubmitRule.java
index db18f0d..85206e5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/TestSubmitRule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/TestSubmitRule.java
@@ -47,7 +47,7 @@
 
 public class TestSubmitRule implements RestModifyView<RevisionResource, Input> {
   public enum Filters {
-    RUN, SKIP;
+    RUN, SKIP
   }
 
   public static class Input {
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 1ed0baed..2b9cb2e 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
@@ -226,6 +226,7 @@
     install(new AuditModule());
     install(new com.google.gerrit.server.access.Module());
     install(new com.google.gerrit.server.account.Module());
+    install(new com.google.gerrit.server.api.Module());
     install(new com.google.gerrit.server.change.Module());
     install(new com.google.gerrit.server.config.Module());
     install(new com.google.gerrit.server.group.Module());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/PluginConfigFactory.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/PluginConfigFactory.java
index 294d8a5..8df7073 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/PluginConfigFactory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/PluginConfigFactory.java
@@ -14,27 +14,45 @@
 
 package com.google.gerrit.server.config;
 
+import com.google.common.collect.Maps;
 import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.git.ProjectLevelConfig;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.project.ProjectState;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
+import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
 
 @Singleton
 public class PluginConfigFactory {
+  private static final Logger log =
+      LoggerFactory.getLogger(PluginConfigFactory.class);
+
+  private final SitePaths site;
   private final Config cfg;
   private final ProjectCache projectCache;
   private final ProjectState.Factory projectStateFactory;
+  private final Map<String, Config> pluginConfigs;
 
   @Inject
-  PluginConfigFactory(@GerritServerConfig Config cfg,
+  PluginConfigFactory(SitePaths site, @GerritServerConfig Config cfg,
       ProjectCache projectCache, ProjectState.Factory projectStateFactory) {
+    this.site = site;
     this.cfg = cfg;
     this.projectCache = projectCache;
     this.projectStateFactory = projectStateFactory;
+    this.pluginConfigs = Maps.newHashMap();
   }
 
   /**
@@ -128,4 +146,96 @@
     return getFromProjectConfig(projectName, pluginName).withInheritance(
         projectStateFactory);
   }
+
+  /**
+   * Returns the configuration for the specified plugin that is stored in the
+   * plugin configuration file 'etc/<plugin-name>.config'.
+   *
+   * The plugin configuration is only loaded once and is then cached.
+   *
+   * @param pluginName the name of the plugin for which the configuration should
+   *        be returned
+   * @return the plugin configuration from the 'etc/<plugin-name>.config' file
+   */
+  public Config getGlobalPluginConfig(String pluginName) {
+    if (pluginConfigs.containsKey(pluginName)) {
+      return pluginConfigs.get(pluginName);
+    }
+
+    File pluginConfigFile = new File(site.etc_dir, pluginName + ".config");
+    FileBasedConfig cfg = new FileBasedConfig(pluginConfigFile, FS.DETECTED);
+    pluginConfigs.put(pluginName, cfg);
+    if (!cfg.getFile().exists()) {
+      log.info("No " + pluginConfigFile.getAbsolutePath() + "; assuming defaults");
+      return cfg;
+    }
+
+    try {
+      cfg.load();
+    } catch (IOException e) {
+      log.warn("Failed to load " + pluginConfigFile.getAbsolutePath(), e);
+    } catch (ConfigInvalidException e) {
+      log.warn("Failed to load " + pluginConfigFile.getAbsolutePath(), e);
+    }
+
+    return cfg;
+  }
+
+  /**
+   * Returns the configuration for the specified plugin that is stored in the
+   * '<plugin-name>.config' file in the 'refs/meta/config' branch of the
+   * specified project.
+   *
+   * @param projectName the name of the project for which the plugin
+   *        configuration should be returned
+   * @param pluginName the name of the plugin for which the configuration should
+   *        be returned
+   * @return the plugin configuration from the '<plugin-name>.config' file of
+   *         the specified project
+   * @throws NoSuchProjectException thrown if the specified project does not
+   *         exist
+   */
+  public Config getProjectPluginConfig(Project.NameKey projectName,
+      String pluginName) throws NoSuchProjectException {
+    return getPluginConfig(projectName, pluginName).get();
+  }
+
+  /**
+   * Returns the configuration for the specified plugin that is stored in the
+   * '<plugin-name>.config' file in the 'refs/meta/config' branch of the
+   * specified project. Parameters which are not set in the
+   * '<plugin-name>.config' of this project are inherited from the parent
+   * project's '<plugin-name>.config' files.
+   *
+   * E.g.: child project: [mySection "mySubsection"] myKey = childValue
+   *
+   * parent project: [mySection "mySubsection"] myKey = parentValue anotherKey =
+   * someValue
+   *
+   * return: [mySection "mySubsection"] myKey = childValue anotherKey =
+   * someValue
+   *
+   * @param projectName the name of the project for which the plugin
+   *        configuration should be returned
+   * @param pluginName the name of the plugin for which the configuration should
+   *        be returned
+   * @return the plugin configuration from the '<plugin-name>.config' file of
+   *         the specified project with inheriting non-set parameters from the
+   *         parent projects
+   * @throws NoSuchProjectException thrown if the specified project does not
+   *         exist
+   */
+  public Config getProjectPluginConfigWithInheritance(Project.NameKey projectName,
+      String pluginName) throws NoSuchProjectException {
+    return getPluginConfig(projectName, pluginName).getWithInheritance();
+  }
+
+  private ProjectLevelConfig getPluginConfig(Project.NameKey projectName,
+      String pluginName) throws NoSuchProjectException {
+    ProjectState projectState = projectCache.get(projectName);
+    if (projectState == null) {
+      throw new NoSuchProjectException(projectName);
+    }
+    return projectState.getConfig(pluginName);
+  }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/documentation/QueryDocumentationExecutor.java b/gerrit-server/src/main/java/com/google/gerrit/server/documentation/QueryDocumentationExecutor.java
index c9d68e8..576ed9f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/documentation/QueryDocumentationExecutor.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/documentation/QueryDocumentationExecutor.java
@@ -82,6 +82,8 @@
     }
     try {
       Query query = parser.parse(q);
+      // TODO(fishywang): Currently as we don't have much documentation, we just use MAX_VALUE here
+      // and skipped paging. Maybe add paging later.
       TopDocs results = searcher.search(query, Integer.MAX_VALUE);
       ScoreDoc[] hits = results.scoreDocs;
       int totalHits = results.totalHits;
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 c51a6ec..43e0156 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
@@ -19,7 +19,6 @@
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.SitePaths;
-import com.google.inject.AbstractModule;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
@@ -62,17 +61,11 @@
   private static final String UNNAMED =
       "Unnamed repository; edit this file to name it for gitweb.";
 
-  public static class Module extends AbstractModule {
+  public static class Module extends LifecycleModule {
     @Override
     protected void configure() {
       bind(GitRepositoryManager.class).to(LocalDiskRepositoryManager.class);
-
-      install(new LifecycleModule() {
-        @Override
-        protected void configure() {
-          listener().to(LocalDiskRepositoryManager.Lifecycle.class);
-        }
-      });
+      listener().to(LocalDiskRepositoryManager.Lifecycle.class);
     }
   }
 
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 aa334f3..40addac 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
@@ -951,7 +951,7 @@
   }
 
   private enum RetryStatus {
-    UNSUBMIT, RETRY_NO_MESSAGE, RETRY_ADD_MESSAGE;
+    UNSUBMIT, RETRY_NO_MESSAGE, RETRY_ADD_MESSAGE
   }
 
   private RetryStatus getRetryStatus(
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/NotifyConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/NotifyConfig.java
index 3a0c278..abc53f4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/NotifyConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/NotifyConfig.java
@@ -25,7 +25,7 @@
 
 public class NotifyConfig implements Comparable<NotifyConfig> {
   public static enum Header {
-    TO, CC, BCC;
+    TO, CC, BCC
   }
 
   private String name;
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
new file mode 100644
index 0000000..fc95608
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectLevelConfig.java
@@ -0,0 +1,97 @@
+// 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.git;
+
+import com.google.common.collect.Iterables;
+import com.google.gerrit.server.project.ProjectState;
+
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.Config;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Set;
+
+/** Configuration file in the projects refs/meta/config branch. */
+public class ProjectLevelConfig extends VersionedMetaData {
+  private final String fileName;
+  private final ProjectState project;
+  private Config cfg;
+
+  public ProjectLevelConfig(String fileName, ProjectState project) {
+    this.fileName = fileName;
+    this.project = project;
+  }
+
+  @Override
+  protected String getRefName() {
+    return GitRepositoryManager.REF_CONFIG;
+  }
+
+  @Override
+  protected void onLoad() throws IOException, ConfigInvalidException {
+    cfg = readConfig(fileName);
+  }
+
+  public Config get() {
+    if (cfg == null) {
+      cfg = new Config();
+    }
+    return cfg;
+  }
+
+  public Config getWithInheritance() {
+    Config cfgWithInheritance = new Config();
+    try {
+      cfgWithInheritance.fromText(get().toText());
+    } catch (ConfigInvalidException e) {
+      // cannot happen
+    }
+    ProjectState parent = Iterables.getFirst(project.parents(), null);
+    if (parent != null) {
+      Config parentCfg = parent.getConfig(fileName).getWithInheritance();
+      for (String section : parentCfg.getSections()) {
+        Set<String> allNames = get().getNames(section);
+        for (String name : parentCfg.getNames(section)) {
+          if (!allNames.contains(name)) {
+            cfgWithInheritance.setStringList(section, null, name,
+                Arrays.asList(parentCfg.getStringList(section, null, name)));
+          }
+        }
+
+        for (String subsection : parentCfg.getSubsections(section)) {
+          allNames = get().getNames(section, subsection);
+          for (String name : parentCfg.getNames(section, subsection)) {
+            if (!allNames.contains(name)) {
+              cfgWithInheritance.setStringList(section, subsection, name,
+                  Arrays.asList(parentCfg.getStringList(section, subsection, name)));
+            }
+          }
+        }
+      }
+    }
+    return cfgWithInheritance;
+  }
+
+  @Override
+  protected void onSave(CommitBuilder commit) throws IOException,
+      ConfigInvalidException {
+    if (commit.getMessage() == null || "".equals(commit.getMessage())) {
+      commit.setMessage("Updated configuration\n");
+    }
+    saveConfig(fileName, cfg);
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/QueueProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/QueueProvider.java
index b539416..c7d925c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/QueueProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/QueueProvider.java
@@ -16,7 +16,7 @@
 
 public interface QueueProvider {
   public static enum QueueType {
-    INTERACTIVE, BATCH;
+    INTERACTIVE, BATCH
   }
 
   public WorkQueue.Executor getQueue(QueueType type);
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 06e88e4..48ad01a 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
@@ -328,7 +328,7 @@
       final ChangeCache changeCache,
       final ChangeInserter.Factory changeInserterFactory,
       final CommitValidators.Factory commitValidatorsFactory,
-      @CanonicalWebUrl @Nullable final String canonicalWebUrl,
+      @CanonicalWebUrl final String canonicalWebUrl,
       @GerritPersonIdent final PersonIdent gerritIdent,
       final TrackingFooters trackingFooters,
       final WorkQueue workQueue,
@@ -404,9 +404,10 @@
         if (allRefs == null) {
           try {
             allRefs = rp.getRepository().getRefDatabase().getRefs(ALL);
+          } catch (ServiceMayNotContinueException e) {
+            throw e;
           } catch (IOException e) {
-            ServiceMayNotContinueException ex =
-                new ServiceMayNotContinueException(e.getMessage());
+            ServiceMayNotContinueException ex = new ServiceMayNotContinueException();
             ex.initCause(e);
             throw ex;
           }
@@ -591,22 +592,42 @@
             return input.created;
           }
         });
-    if (!Iterables.isEmpty(created) && canonicalWebUrl != null) {
-      final String url = canonicalWebUrl;
+    if (!Iterables.isEmpty(created)) {
       addMessage("");
       addMessage("New Changes:");
       for (CreateRequest c : created) {
-        StringBuilder m = new StringBuilder()
-            .append("  ")
-            .append(url)
-            .append(c.change.getChangeId());
-        if (c.change.getStatus() == Change.Status.DRAFT) {
-          m.append(" [DRAFT]");
-        }
-        addMessage(m.toString());
+        addMessage(formatChangeUrl(canonicalWebUrl, c.change));
       }
       addMessage("");
     }
+
+    Iterable<ReplaceRequest> updated =
+        Iterables.filter(replaceByChange.values(),
+            new Predicate<ReplaceRequest>() {
+              @Override
+              public boolean apply(ReplaceRequest input) {
+                return !input.skip;
+              }
+            });
+    if (!Iterables.isEmpty(updated)) {
+      addMessage("");
+      addMessage("Updated Changes:");
+      for (ReplaceRequest u : updated) {
+        addMessage(formatChangeUrl(canonicalWebUrl, u.change));
+      }
+      addMessage("");
+    }
+  }
+
+  private static String formatChangeUrl(String url, Change change) {
+    StringBuilder m = new StringBuilder()
+        .append("  ")
+        .append(url)
+        .append(change.getChangeId());
+    if (change.getStatus() == Change.Status.DRAFT) {
+      m.append(" [DRAFT]");
+    }
+    return m.toString();
   }
 
   private void insertChangesAndPatchSets() {
@@ -960,10 +981,10 @@
     RefControl ctl;
     Set<Account.Id> reviewer = Sets.newLinkedHashSet();
     Set<Account.Id> cc = Sets.newLinkedHashSet();
-    RevCommit baseCommit;
+    List<RevCommit> baseCommit;
 
     @Option(name = "--base", metaVar = "BASE", usage = "merge base of changes")
-    ObjectId base;
+    List<ObjectId> base;
 
     @Option(name = "--topic", metaVar = "NAME", usage = "attach topic to changes")
     String topic;
@@ -1114,20 +1135,24 @@
 
     RevWalk walk = rp.getRevWalk();
     if (magicBranch.base != null) {
-      try {
-        magicBranch.baseCommit = walk.parseCommit(magicBranch.base);
-      } catch (IncorrectObjectTypeException notCommit) {
-        reject(cmd, "base must be a commit");
-        return;
-      } catch (MissingObjectException e) {
-        reject(cmd, "base not found");
-        return;
-      } catch (IOException e) {
-        log.warn(String.format(
-            "Project %s cannot read %s",
-            project.getName(), magicBranch.base.name()), e);
-        reject(cmd, "internal server error");
-        return;
+      magicBranch.baseCommit = Lists.newArrayListWithCapacity(
+          magicBranch.base.size());
+      for (ObjectId id : magicBranch.base) {
+        try {
+          magicBranch.baseCommit.add(walk.parseCommit(id));
+        } catch (IncorrectObjectTypeException notCommit) {
+          reject(cmd, "base must be a commit");
+          return;
+        } catch (MissingObjectException e) {
+          reject(cmd, "base not found");
+          return;
+        } catch (IOException e) {
+          log.warn(String.format(
+              "Project %s cannot read %s",
+              project.getName(), id.name()), e);
+          reject(cmd, "internal server error");
+          return;
+        }
       }
     }
 
@@ -1267,7 +1292,9 @@
       Set<ObjectId> existing = Sets.newHashSet();
       walk.markStart(walk.parseCommit(magicBranch.cmd.getNewId()));
       if (magicBranch.baseCommit != null) {
-        walk.markUninteresting(magicBranch.baseCommit);
+        for (RevCommit c : magicBranch.baseCommit) {
+          walk.markUninteresting(c);
+        }
         assert magicBranch.ctl != null;
         Ref targetRef = allRefs.get(magicBranch.ctl.getRefName());
         if (targetRef != null) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsAdvertiseRefsHook.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsAdvertiseRefsHook.java
index 530a388..f34ce8b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsAdvertiseRefsHook.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsAdvertiseRefsHook.java
@@ -68,9 +68,10 @@
     if (oldRefs == null) {
       try {
         oldRefs = rp.getRepository().getRefDatabase().getRefs(ALL);
+      } catch (ServiceMayNotContinueException e) {
+        throw e;
       } catch (IOException e) {
-        ServiceMayNotContinueException ex =
-            new ServiceMayNotContinueException(e.getMessage());
+        ServiceMayNotContinueException ex = new ServiceMayNotContinueException();
         ex.initCause(e);
         throw ex;
       }
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 8c65b1a..14aae94 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
@@ -127,9 +127,10 @@
       RevWalk revWalk) throws ServiceMayNotContinueException {
     try {
       return filter(repository.getRefDatabase().getRefs(RefDatabase.ALL));
+    } catch (ServiceMayNotContinueException e) {
+      throw e;
     } catch (IOException e) {
-      ServiceMayNotContinueException ex =
-          new ServiceMayNotContinueException(e.getMessage());
+      ServiceMayNotContinueException ex = new ServiceMayNotContinueException();
       ex.initCause(e);
       throw ex;
     }
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 64210a0..ab145e6 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
@@ -241,7 +241,7 @@
       // prefer to see tasks sorted in: done before running,
       // running before ready, ready before sleeping.
       //
-      DONE, CANCELLED, RUNNING, READY, SLEEPING, OTHER;
+      DONE, CANCELLED, RUNNING, READY, SLEEPING, OTHER
     }
 
     private final Runnable runnable;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexModule.java
index 2cfc93d..4d285f1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexModule.java
@@ -37,7 +37,7 @@
  */
 public class IndexModule extends LifecycleModule {
   public enum IndexType {
-    SQL, LUCENE, SOLR;
+    SQL, LUCENE, SOLR
   }
 
   /** Type of secondary index. */
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 cd6409e..cb92b0f 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
@@ -17,13 +17,13 @@
 import com.google.common.base.Strings;
 import com.google.common.collect.Ordering;
 import com.google.gerrit.common.errors.EmailException;
+import com.google.gerrit.extensions.api.changes.ReviewInput.NotifyHandling;
 import com.google.gerrit.reviewdb.client.AccountProjectWatch.NotifyType;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.CommentRange;
 import com.google.gerrit.reviewdb.client.Patch;
 import com.google.gerrit.reviewdb.client.PatchLineComment;
 import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gerrit.server.change.PostReview.NotifyHandling;
 import com.google.gerrit.server.patch.PatchFile;
 import com.google.gerrit.server.patch.PatchList;
 import com.google.gerrit.server.patch.PatchListNotAvailableException;
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 89fc6b9..b32e7f4 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
@@ -51,7 +51,7 @@
   }
 
   public static enum Encryption {
-    NONE, SSL, TLS;
+    NONE, SSL, TLS
   }
 
   private final boolean enabled;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchFile.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchFile.java
index 6fcf581..81f4352 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchFile.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchFile.java
@@ -31,7 +31,6 @@
 import org.eclipse.jgit.treewalk.TreeWalk;
 
 import java.io.IOException;
-import java.nio.charset.CharacterCodingException;
 
 /** State supporting processing of a single {@link Patch} instance. */
 public class PatchFile {
@@ -89,7 +88,6 @@
    * @throws CorruptEntityException the patch cannot be read.
    * @throws IOException the patch or complete file content cannot be read.
    * @throws NoSuchEntityException
-   * @throws CharacterCodingException the file is not a known character set.
    */
   public String getLine(final int file, final int line)
       throws CorruptEntityException, IOException, NoSuchEntityException {
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 e1294e0..b71d04a 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,8 +311,8 @@
         MergeFormatter fmt = new MergeFormatter();
         Map<String, MergeResult<? extends Sequence>> r = m.getMergeResults();
         Map<String, ObjectId> resolved = new HashMap<String, ObjectId>();
-        for (String path : r.keySet()) {
-          MergeResult<? extends Sequence> p = r.get(path);
+        for (Map.Entry<String, MergeResult<? extends Sequence>> entry : r.entrySet()) {
+          MergeResult<? extends Sequence> p = entry.getValue();
           TemporaryBuffer buf = new TemporaryBuffer.LocalFile(10 * 1024 * 1024);
           try {
             fmt.formatMerge(buf, p, "BASE", oursName, theirsName, "UTF-8");
@@ -320,7 +320,7 @@
 
             InputStream in = buf.openInputStream();
             try {
-              resolved.put(path, ins.insert(Constants.OBJ_BLOB, buf.length(), in));
+              resolved.put(entry.getKey(), ins.insert(Constants.OBJ_BLOB, buf.length(), in));
             } finally {
               in.close();
             }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/CleanupHandle.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/CleanupHandle.java
index b04f337..593f2c9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/CleanupHandle.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/CleanupHandle.java
@@ -32,6 +32,7 @@
     try {
       jarFile.close();
     } catch (IOException err) {
+      PluginLoader.log.error("Cannot close " + jarFile.getName(), err);
     }
     if (!tmpFile.delete() && tmpFile.exists()) {
       PluginLoader.log.warn("Cannot delete " + tmpFile.getAbsolutePath()
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/Plugin.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/Plugin.java
index d9a2c0f..9bf4085 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/Plugin.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/Plugin.java
@@ -34,7 +34,7 @@
 
 public abstract class Plugin {
   public static enum ApiType {
-    EXTENSION, PLUGIN, JS;
+    EXTENSION, PLUGIN, JS
   }
 
   /** Unique key that changes whenever a plugin reloads. */
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 ea19fe3..4682d2b 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
@@ -349,8 +349,9 @@
     syncDisabledPlugins(jars);
 
     Map<String, File> activePlugins = filterDisabled(jars);
-    for (String name : activePlugins.keySet()) {
-      File jar = activePlugins.get(name);
+    for (Map.Entry<String, File> entry : activePlugins.entrySet()) {
+      String name = entry.getKey();
+      File jar = entry.getValue();
       FileSnapshot brokenTime = broken.get(name);
       if (brokenTime != null && !brokenTime.isModified(jar)) {
         continue;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginModule.java
index bd1c3c8..055baf1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginModule.java
@@ -16,9 +16,8 @@
 
 import com.google.gerrit.extensions.systemstatus.ServerInformation;
 import com.google.gerrit.lifecycle.LifecycleModule;
-import com.google.inject.AbstractModule;
 
-public class PluginModule extends AbstractModule {
+public class PluginModule extends LifecycleModule {
   @Override
   protected void configure() {
     bind(ServerInformationImpl.class);
@@ -28,11 +27,6 @@
     bind(PluginGuiceEnvironment.class);
     bind(PluginLoader.class);
     bind(CopyConfigModule.class);
-    install(new LifecycleModule() {
-      @Override
-      protected void configure() {
-        listener().to(PluginLoader.class);
-      }
-    });
+    listener().to(PluginLoader.class);
   }
 }
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 d87db2f..5c40d16 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
@@ -94,6 +94,15 @@
       return controlFor(change, user);
     }
 
+    public ChangeControl validateFor(Change change, CurrentUser user)
+        throws NoSuchChangeException, OrmException {
+      ChangeControl c = controlFor(change, user);
+      if (!c.isVisible(db.get())) {
+        throw new NoSuchChangeException(c.getChange().getId());
+      }
+      return c;
+    }
+
     public ChangeControl validateFor(Change.Id id, CurrentUser user)
         throws NoSuchChangeException, OrmException {
       ChangeControl c = controlFor(id, user);
@@ -157,6 +166,19 @@
     }
   }
 
+  /**
+   * Exception thrown when the label term of a submit record
+   * unexpectedly didn't contain a user term.
+   */
+  private static class UserTermExpected extends Exception {
+    private static final long serialVersionUID = 1L;
+
+    public UserTermExpected(SubmitRecord.Label label) {
+      super(String.format("A label with the status %s must contain a user.",
+          label.toString()));
+    }
+  }
+
   private final RefControl refControl;
   private final Change change;
 
@@ -495,25 +517,29 @@
         lbl.label = state.arg(0).name();
         Term status = state.arg(1);
 
-        if ("ok".equals(status.name())) {
-          lbl.status = SubmitRecord.Label.Status.OK;
-          appliedBy(lbl, status);
+        try {
+          if ("ok".equals(status.name())) {
+            lbl.status = SubmitRecord.Label.Status.OK;
+            appliedBy(lbl, status);
 
-        } else if ("reject".equals(status.name())) {
-          lbl.status = SubmitRecord.Label.Status.REJECT;
-          appliedBy(lbl, status);
+          } else if ("reject".equals(status.name())) {
+            lbl.status = SubmitRecord.Label.Status.REJECT;
+            appliedBy(lbl, status);
 
-        } else if ("need".equals(status.name())) {
-          lbl.status = SubmitRecord.Label.Status.NEED;
+          } else if ("need".equals(status.name())) {
+            lbl.status = SubmitRecord.Label.Status.NEED;
 
-        } else if ("may".equals(status.name())) {
-          lbl.status = SubmitRecord.Label.Status.MAY;
+          } else if ("may".equals(status.name())) {
+            lbl.status = SubmitRecord.Label.Status.MAY;
 
-        } else if ("impossible".equals(status.name())) {
-          lbl.status = SubmitRecord.Label.Status.IMPOSSIBLE;
+          } else if ("impossible".equals(status.name())) {
+            lbl.status = SubmitRecord.Label.Status.IMPOSSIBLE;
 
-        } else {
-          return logInvalidResult(submitRule, submitRecord);
+          } else {
+            return logInvalidResult(submitRule, submitRecord);
+          }
+        } catch (UserTermExpected e) {
+          return logInvalidResult(submitRule, submitRecord, e.getMessage());
         }
       }
 
@@ -584,9 +610,14 @@
     }
   }
 
-  private List<SubmitRecord> logInvalidResult(Term rule, Term record) {
+  private List<SubmitRecord> logInvalidResult(Term rule, Term record, String reason) {
     return logRuleError("Submit rule " + rule + " for change " + change.getId()
-        + " of " + getProject().getName() + " output invalid result: " + record);
+        + " of " + getProject().getName() + " output invalid result: " + record
+        + (reason == null ? "" : ". Reason: " + reason));
+  }
+
+  private List<SubmitRecord> logInvalidResult(Term rule, Term record) {
+    return logInvalidResult(rule, record, null);
   }
 
   private List<SubmitRecord> logRuleError(String err, Exception e) {
@@ -629,11 +660,14 @@
     return rec;
   }
 
-  private void appliedBy(SubmitRecord.Label label, Term status) {
+  private void appliedBy(SubmitRecord.Label label, Term status)
+      throws UserTermExpected {
     if (status.isStructure() && status.arity() == 1) {
       Term who = status.arg(0);
       if (isUser(who)) {
         label.appliedBy = new Account.Id(((IntegerTerm) who.arg(0)).intValue());
+      } else {
+        throw new UserTermExpected(label);
       }
     }
   }
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 59b544a..f777039 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
@@ -271,6 +271,7 @@
               info.name = parentState.getProject().getName();
               info.description = Strings.emptyToNull(
                   parentState.getProject().getDescription());
+              info.state = parentState.getProject().getState();
             } else {
               rejected.add(parentState.getProject().getName());
               continue;
@@ -313,6 +314,8 @@
             info.description = Strings.emptyToNull(e.getProject().getDescription());
           }
 
+          info.state = e.getProject().getState();
+
           try {
             if (!showBranch.isEmpty()) {
               Repository git = repoManager.openRepository(projectName);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectJson.java
index 8db5cbb..72910a3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectJson.java
@@ -41,6 +41,7 @@
     Project.NameKey parentName = p.getParent(allProjects);
     info.parent = parentName != null ? parentName.get() : null;
     info.description = Strings.emptyToNull(p.getDescription());
+    info.state = p.getState();
     info.finish();
     return info;
   }
@@ -51,6 +52,7 @@
     public String name;
     public String parent;
     public String description;
+    public Project.State state;
     public Map<String, String> branches;
 
     void finish() {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectResource.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectResource.java
index f4449f0..459e392 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectResource.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectResource.java
@@ -41,6 +41,10 @@
     return control.getProject().getNameKey();
   }
 
+  public Project.State getState() {
+    return control.getProject().getState();
+  }
+
   public ProjectControl getControl() {
     return control;
   }
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 800fa6e..2e79e2f 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
@@ -40,12 +40,14 @@
 import com.google.gerrit.server.config.SitePaths;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.ProjectConfig;
+import com.google.gerrit.server.git.ProjectLevelConfig;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
 import com.googlecode.prolog_cafe.compiler.CompileException;
 import com.googlecode.prolog_cafe.lang.PrologMachineCopy;
 
+import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Repository;
 import org.slf4j.Logger;
@@ -83,6 +85,7 @@
   private final List<CommentLinkInfo> commentLinks;
 
   private final ProjectConfig config;
+  private final Map<String, ProjectLevelConfig> configs;
   private final Set<AccountGroup.UUID> localOwners;
 
   /** Prolog rule state. */
@@ -121,6 +124,7 @@
     this.rulesCache = rulesCache;
     this.commentLinks = commentLinks;
     this.config = config;
+    this.configs = Maps.newHashMap();
     this.capabilities = isAllProjects
       ? new CapabilityCollection(config.getAccessSection(AccessSection.GLOBAL_CAPABILITIES))
       : null;
@@ -216,6 +220,29 @@
     return config;
   }
 
+  public ProjectLevelConfig getConfig(String fileName) {
+    if (configs.containsKey(fileName)) {
+      return configs.get(fileName);
+    }
+
+    ProjectLevelConfig cfg = new ProjectLevelConfig(fileName, this);
+    try {
+      Repository git = gitMgr.openRepository(getProject().getNameKey());
+      try {
+        cfg.load(git);
+      } finally {
+        git.close();
+      }
+    } catch (IOException e) {
+      log.warn("Failed to load " + fileName + " for " + getProject().getName(), e);
+    } catch (ConfigInvalidException e) {
+      log.warn("Failed to load " + fileName + " for " + getProject().getName(), e);
+    }
+
+    configs.put(fileName, cfg);
+    return cfg;
+  }
+
   public long getMaxObjectSizeLimit() {
     return config.getMaxObjectSizeLimit();
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/SetParent.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/SetParent.java
index 999358c..28175e2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/SetParent.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/SetParent.java
@@ -38,7 +38,7 @@
 
 import java.io.IOException;
 
-class SetParent implements RestModifyView<ProjectResource, Input> {
+public class SetParent implements RestModifyView<ProjectResource, Input> {
   static class Input {
     @DefaultInput
     String parent;
@@ -63,41 +63,14 @@
       BadRequestException, ResourceConflictException,
       ResourceNotFoundException, UnprocessableEntityException, IOException {
     ProjectControl ctl = rsrc.getControl();
+    validateParentUpdate(ctl, input.parent);
     IdentifiedUser user = (IdentifiedUser) ctl.getCurrentUser();
-    if (!user.getCapabilities().canAdministrateServer()) {
-      throw new AuthException("not administrator");
-    }
-
-    if (rsrc.getNameKey().equals(allProjects)) {
-      throw new ResourceConflictException("cannot set parent of "
-          + allProjects.get());
-    }
-
-    input.parent = Strings.emptyToNull(input.parent);
-    if (input.parent != null) {
-      ProjectState parent = cache.get(new Project.NameKey(input.parent));
-      if (parent == null) {
-        throw new UnprocessableEntityException("parent project " + input.parent
-            + " not found");
-      }
-
-      if (Iterables.tryFind(parent.tree(), new Predicate<ProjectState>() {
-        @Override
-        public boolean apply(ProjectState input) {
-          return input.getProject().getNameKey().equals(rsrc.getNameKey());
-        }
-      }).isPresent()) {
-        throw new ResourceConflictException("cycle exists between "
-            + rsrc.getName() + " and " + parent.getProject().getName());
-      }
-    }
-
     try {
       MetaDataUpdate md = updateFactory.create(rsrc.getNameKey());
       try {
         ProjectConfig config = ProjectConfig.read(md);
         Project project = config.getProject();
-        project.setParentName(input.parent);
+        project.setParentName(Strings.emptyToNull(input.parent));
 
         String msg = Strings.emptyToNull(input.commitMessage);
         if (msg == null) {
@@ -124,4 +97,39 @@
           "invalid project.config: %s", e.getMessage()));
     }
   }
+
+  public void validateParentUpdate(final ProjectControl ctl, String newParent)
+      throws AuthException, ResourceConflictException,
+      UnprocessableEntityException {
+    IdentifiedUser user = (IdentifiedUser) ctl.getCurrentUser();
+    if (!user.getCapabilities().canAdministrateServer()) {
+      throw new AuthException("not administrator");
+    }
+
+    if (ctl.getProject().getNameKey().equals(allProjects)) {
+      throw new ResourceConflictException("cannot set parent of "
+          + allProjects.get());
+    }
+
+    newParent = Strings.emptyToNull(newParent);
+    if (newParent != null) {
+      ProjectState parent = cache.get(new Project.NameKey(newParent));
+      if (parent == null) {
+        throw new UnprocessableEntityException("parent project " + newParent
+            + " not found");
+      }
+
+      if (Iterables.tryFind(parent.tree(), new Predicate<ProjectState>() {
+        @Override
+        public boolean apply(ProjectState input) {
+          return input.getProject().getNameKey()
+              .equals(ctl.getProject().getNameKey());
+        }
+      }).isPresent()) {
+        throw new ResourceConflictException("cycle exists between "
+            + ctl.getProject().getName() + " and "
+            + parent.getProject().getName());
+      }
+    }
+  }
 }
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 0efdc88..37890a5 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
@@ -85,6 +85,7 @@
   public static final String FIELD_CHANGE = "change";
   public static final String FIELD_COMMENT = "comment";
   public static final String FIELD_COMMIT = "commit";
+  public static final String FIELD_CONFLICTS = "conflicts";
   public static final String FIELD_DRAFTBY = "draftby";
   public static final String FIELD_FILE = "file";
   public static final String FIELD_IS = "is";
@@ -226,10 +227,7 @@
           .parse(query));
 
     } else if (PAT_CHANGE_ID.matcher(query).matches()) {
-      if (query.charAt(0) == 'i') {
-        query = "I" + query.substring(1);
-      }
-      return new ChangeIdPredicate(args.dbProvider, query);
+      return new ChangeIdPredicate(args.dbProvider, parseChangeId(query));
     }
 
     throw new IllegalArgumentException();
@@ -316,6 +314,14 @@
   }
 
   @Operator
+  public Predicate<ChangeData> conflicts(String value) throws OrmException,
+      QueryParseException {
+    requireIndex(FIELD_CONFLICTS, value);
+    return new ConflictsPredicate(args.dbProvider, args.patchListCache, value,
+        parseChange(value));
+  }
+
+  @Operator
   public Predicate<ChangeData> project(String name) {
     if (name.startsWith("^"))
       return new RegexProjectPredicate(args.dbProvider, name);
@@ -679,6 +685,31 @@
     return g;
   }
 
+  private List<Change> parseChange(String value) throws OrmException,
+      QueryParseException {
+    if (PAT_LEGACY_ID.matcher(value).matches()) {
+      return Collections.singletonList(args.dbProvider.get().changes()
+          .get(Change.Id.parse(value)));
+    } else if (PAT_CHANGE_ID.matcher(value).matches()) {
+      Change.Key a = new Change.Key(parseChangeId(value));
+      List<Change> changes =
+          args.dbProvider.get().changes().byKeyRange(a, a.max()).toList();
+      if (changes.isEmpty()) {
+        throw error("Change " + value + " not found");
+      }
+      return changes;
+    }
+
+    throw error("Change " + value + " not found");
+  }
+
+  private static String parseChangeId(String value) {
+    if (value.charAt(0) == 'i') {
+      value = "I" + value.substring(1);
+    }
+    return value;
+  }
+
   private Account.Id self() {
     if (currentUser.isIdentifiedUser()) {
       return ((IdentifiedUser) currentUser).getAccountId();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ConflictsPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ConflictsPredicate.java
new file mode 100644
index 0000000..e398bb3
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ConflictsPredicate.java
@@ -0,0 +1,68 @@
+// 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.query.change;
+
+import com.google.common.collect.Lists;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.patch.PatchListCache;
+import com.google.gerrit.server.query.OrPredicate;
+import com.google.gerrit.server.query.Predicate;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Provider;
+
+import java.util.List;
+
+class ConflictsPredicate extends OrPredicate<ChangeData> {
+  private final String value;
+
+  ConflictsPredicate(Provider<ReviewDb> db, PatchListCache plc, String value,
+      List<Change> changes) throws OrmException {
+    super(predicates(db, plc, changes));
+    this.value = value;
+  }
+
+  private static List<Predicate<ChangeData>> predicates(Provider<ReviewDb> db,
+      PatchListCache plc, List<Change> changes) throws OrmException {
+    List<Predicate<ChangeData>> changePredicates =
+        Lists.newArrayListWithCapacity(changes.size());
+    for (Change c : changes) {
+      List<String> files = new ChangeData(c).currentFilePaths(db, plc);
+      List<Predicate<ChangeData>> filePredicates =
+          Lists.newArrayListWithCapacity(files.size());
+      for (String file : files) {
+        filePredicates.add(new EqualsFilePredicate(db, plc, file));
+      }
+
+      List<Predicate<ChangeData>> predicatesForOneChange =
+          Lists.newArrayListWithCapacity(4);
+      predicatesForOneChange.add(
+          not(new LegacyChangeIdPredicate(db, c.getId())));
+      predicatesForOneChange.add(
+          new ProjectPredicate(db, c.getProject().get()));
+      predicatesForOneChange.add(
+          new RefPredicate(db, c.getDest().get()));
+      predicatesForOneChange.add(or(filePredicates));
+
+      changePredicates.add(and(predicatesForOneChange));
+    }
+    return changePredicates;
+  }
+
+  @Override
+  public String toString() {
+    return ChangeQueryBuilder.FIELD_CONFLICTS + ":" + value;
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryChanges.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryChanges.java
index 44c71a9..4b6a5a6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryChanges.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryChanges.java
@@ -24,7 +24,6 @@
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.change.ChangeJson;
 import com.google.gerrit.server.change.ChangeJson.ChangeInfo;
-import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.query.QueryParseException;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
@@ -82,16 +81,12 @@
   }
 
   @Inject
-  QueryChanges(ChangeJson json,
-      QueryProcessor qp,
-      ChangeControl.Factory cf,
-      Provider<CurrentUser> user) {
+  QueryChanges(ChangeJson json, QueryProcessor qp, Provider<CurrentUser> user) {
     this.json = json;
     this.imp = qp;
     this.user = user;
 
     options = EnumSet.noneOf(ListChangesOption.class);
-    json.setChangeControlFactory(cf);
   }
 
   public void addQuery(String query) {
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 e569ff5..f6fb4c5 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
@@ -86,7 +86,7 @@
       };
 
   public static enum OutputFormat {
-    TEXT, JSON;
+    TEXT, JSON
   }
 
   private final Gson gson = new Gson();
@@ -98,7 +98,8 @@
   private final ChangeQueryRewriter queryRewriter;
   private final Provider<ReviewDb> db;
   private final GitRepositoryManager repoManager;
-  private final ChangeControl.Factory changeControlFactory;
+  private final ChangeControl.GenericFactory changeControlFactory;
+  private final CurrentUser user;
   private final int maxLimit;
 
   private OutputFormat outputFormat = OutputFormat.TEXT;
@@ -124,13 +125,14 @@
       ChangeQueryBuilder.Factory queryBuilder, CurrentUser currentUser,
       ChangeQueryRewriter queryRewriter, Provider<ReviewDb> db,
       GitRepositoryManager repoManager,
-      ChangeControl.Factory changeControlFactory) {
+      ChangeControl.GenericFactory changeControlFactory) {
     this.eventFactory = eventFactory;
     this.queryBuilder = queryBuilder.create(currentUser);
     this.queryRewriter = queryRewriter;
     this.db = db;
     this.repoManager = repoManager;
     this.changeControlFactory = changeControlFactory;
+    this.user = currentUser;
     this.maxLimit = currentUser.getCapabilities()
       .getRange(GlobalCapability.QUERY_LIMIT)
       .getMax();
@@ -303,8 +305,11 @@
         List<ChangeData> results = queryChanges(queryString);
         ChangeAttribute c = null;
         for (ChangeData d : results) {
-          LabelTypes labelTypes = changeControlFactory.controlFor(d.getChange())
-              .getLabelTypes();
+          ChangeControl cc = d.changeControl();
+          if (cc == null || cc.getCurrentUser() != user) {
+            cc = changeControlFactory.controlFor(d.change(db), user);
+          }
+          LabelTypes labelTypes = cc.getLabelTypes();
           c = eventFactory.asChangeAttribute(d.getChange());
           eventFactory.extend(c, d.getChange());
           eventFactory.addTrackingIds(c, d.trackingIds(db));
@@ -316,7 +321,7 @@
           if (includeSubmitRecords) {
             PatchSet.Id psId = d.getChange().currentPatchSetId();
             PatchSet patchSet = db.get().patchSets().get(psId);
-            List<SubmitRecord> submitResult = d.changeControl().canSubmit( //
+            List<SubmitRecord> submitResult = cc.canSubmit( //
                 db.get(), patchSet, null, false, true, true);
             eventFactory.addSubmitRecords(c, submitResult);
           }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/DataSourceProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/DataSourceProvider.java
index c96ed42..a6e3488 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/DataSourceProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/DataSourceProvider.java
@@ -84,7 +84,7 @@
   }
 
   public static enum Context {
-    SINGLE_USER, MULTI_USER;
+    SINGLE_USER, MULTI_USER
   }
 
   private DataSource open(final SitePaths site, final Config cfg,
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_57.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_57.java
index 0edbc06..4b4f5456 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_57.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_57.java
@@ -43,6 +43,7 @@
 
 import java.io.IOException;
 import java.sql.PreparedStatement;
+import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.Collections;
 
@@ -101,7 +102,17 @@
 
         // Prepare the account_group_includes query
         PreparedStatement stmt = ((JdbcSchema) db).getConnection().
-            prepareStatement("SELECT * FROM account_group_includes WHERE group_id = ?");
+            prepareStatement("SELECT COUNT(1) FROM account_group_includes WHERE group_id = ?");
+        boolean isAccountGroupEmpty = false;
+        try {
+          stmt.setInt(1, sc.batchUsersGroupId.get());
+          ResultSet rs = stmt.executeQuery();
+          if (rs.next()) {
+            isAccountGroupEmpty = rs.getInt(1) == 0;
+          }
+        } finally {
+          stmt.close();
+        }
 
         for (String name : createGroupList) {
           AccountGroup.NameKey key = new AccountGroup.NameKey(name);
@@ -125,10 +136,10 @@
         }
 
         AccountGroup batch = db.accountGroups().get(sc.batchUsersGroupId);
-        stmt.setInt(1, sc.batchUsersGroupId.get());
+
         if (batch != null
             && db.accountGroupMembers().byGroup(sc.batchUsersGroupId).toList().isEmpty()
-            &&  stmt.executeQuery().first() != false) {
+            && !isAccountGroupEmpty) {
           // If the batch user group is not used, delete it.
           //
           db.accountGroups().delete(Collections.singleton(batch));
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 f884c73..4a2c477 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
@@ -45,7 +45,7 @@
     // Grab all the groups since we don't have the cache available
     HashMap<AccountGroup.Id, AccountGroup.UUID> allGroups =
         new HashMap<AccountGroup.Id, AccountGroup.UUID>();
-    for( AccountGroup ag : db.accountGroups().all() ) {
+    for (AccountGroup ag : db.accountGroups().all()) {
       allGroups.put(ag.getId(), ag.getGroupUUID());
     }
 
@@ -58,54 +58,58 @@
 
     // Iterate over all entries in account_group_includes
     Statement oldGroupIncludesStmt = conn.createStatement();
-    ResultSet oldGroupIncludes = oldGroupIncludesStmt.
-        executeQuery("SELECT * FROM account_group_includes");
-    while (oldGroupIncludes.next()) {
-      AccountGroup.Id oldGroupId =
-          new AccountGroup.Id(oldGroupIncludes.getInt("group_id"));
-      AccountGroup.Id oldIncludeId =
-          new AccountGroup.Id(oldGroupIncludes.getInt("include_id"));
-      AccountGroup.UUID uuidFromIncludeId = allGroups.get(oldIncludeId);
+    try {
+      ResultSet oldGroupIncludes = oldGroupIncludesStmt.
+          executeQuery("SELECT * FROM account_group_includes");
+      while (oldGroupIncludes.next()) {
+        AccountGroup.Id oldGroupId =
+            new AccountGroup.Id(oldGroupIncludes.getInt("group_id"));
+        AccountGroup.Id oldIncludeId =
+            new AccountGroup.Id(oldGroupIncludes.getInt("include_id"));
+        AccountGroup.UUID uuidFromIncludeId = allGroups.get(oldIncludeId);
 
-      // If we've got an include, but the group no longer exists, don't bother converting
-      if (uuidFromIncludeId == null) {
-        ui.message("Skipping group_id = \"" + oldIncludeId.get() +
-            "\", not a current group");
-        continue;
-      }
-
-      // Create the new include entry
-      AccountGroupById destIncludeEntry = new AccountGroupById(
-          new AccountGroupById.Key(oldGroupId, uuidFromIncludeId));
-
-      // Iterate over all the audits (for this group)
-      PreparedStatement oldAuditsQuery = conn.prepareStatement(
-          "SELECT * FROM account_group_includes_audit WHERE group_id=? AND include_id=?");
-      oldAuditsQuery.setInt(1, oldGroupId.get());
-      oldAuditsQuery.setInt(2, oldIncludeId.get());
-      ResultSet oldGroupIncludeAudits = oldAuditsQuery.executeQuery();
-      while (oldGroupIncludeAudits.next()) {
-        Account.Id addedBy = new Account.Id(oldGroupIncludeAudits.getInt("added_by"));
-        int removedBy = oldGroupIncludeAudits.getInt("removed_by");
-
-        // Create the new audit entry
-        AccountGroupByIdAud destAuditEntry =
-            new AccountGroupByIdAud(destIncludeEntry, addedBy,
-                oldGroupIncludeAudits.getTimestamp("added_on"));
-
-        // If this was a "removed on" entry, note that
-        if (removedBy > 0) {
-          destAuditEntry.removed(new Account.Id(removedBy),
-              oldGroupIncludeAudits.getTimestamp("removed_on"));
+        // If we've got an include, but the group no longer exists, don't bother converting
+        if (uuidFromIncludeId == null) {
+          ui.message("Skipping group_id = \"" + oldIncludeId.get() +
+              "\", not a current group");
+          continue;
         }
-        newIncludeAudits.add(destAuditEntry);
+
+        // Create the new include entry
+        AccountGroupById destIncludeEntry = new AccountGroupById(
+            new AccountGroupById.Key(oldGroupId, uuidFromIncludeId));
+
+        // Iterate over all the audits (for this group)
+        PreparedStatement oldAuditsQueryStmt = conn.prepareStatement(
+            "SELECT * FROM account_group_includes_audit WHERE group_id=? AND include_id=?");
+        try {
+          oldAuditsQueryStmt.setInt(1, oldGroupId.get());
+          oldAuditsQueryStmt.setInt(2, oldIncludeId.get());
+          ResultSet oldGroupIncludeAudits = oldAuditsQueryStmt.executeQuery();
+          while (oldGroupIncludeAudits.next()) {
+            Account.Id addedBy = new Account.Id(oldGroupIncludeAudits.getInt("added_by"));
+            int removedBy = oldGroupIncludeAudits.getInt("removed_by");
+
+            // Create the new audit entry
+            AccountGroupByIdAud destAuditEntry =
+                new AccountGroupByIdAud(destIncludeEntry, addedBy,
+                    oldGroupIncludeAudits.getTimestamp("added_on"));
+
+            // If this was a "removed on" entry, note that
+            if (removedBy > 0) {
+              destAuditEntry.removed(new Account.Id(removedBy),
+                  oldGroupIncludeAudits.getTimestamp("removed_on"));
+            }
+            newIncludeAudits.add(destAuditEntry);
+          }
+          newIncludes.add(destIncludeEntry);
+        } finally {
+          oldAuditsQueryStmt.close();
+        }
       }
-      newIncludes.add(destIncludeEntry);
-      oldAuditsQuery.close();
-      oldGroupIncludeAudits.close();
+    } finally {
+      oldGroupIncludesStmt.close();
     }
-    oldGroupIncludes.close();
-    oldGroupIncludesStmt.close();
 
     // Now insert all of the new entries to the database
     db.accountGroupById().insert(newIncludes);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_77.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_77.java
index 472bc25..80639d6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_77.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_77.java
@@ -199,51 +199,40 @@
 
   static LegacyLabelTypes getLegacyTypes(ReviewDb db) throws SQLException {
     List<LegacyLabelType> types = Lists.newArrayListWithCapacity(2);
-    Statement catStmt = null;
-    PreparedStatement valStmt = null;
-    ResultSet catRs = null;
+    Statement catStmt = ((JdbcSchema) db).getConnection().createStatement();
     try {
-      catStmt = ((JdbcSchema) db).getConnection().createStatement();
-      catRs = catStmt.executeQuery(
+      ResultSet catRs = catStmt.executeQuery(
           "SELECT category_id, name, abbreviated_name, function_name, "
           + " copy_min_score"
           + " FROM approval_categories"
           + " ORDER BY position, name");
-      valStmt = ((JdbcSchema) db).getConnection().prepareStatement(
-          "SELECT value, name"
-          + " FROM approval_category_values"
-          + " WHERE category_id = ?");
-      while (catRs.next()) {
-        String id = catRs.getString("category_id");
-        valStmt.setString(1, id);
-        List<LabelValue> values = Lists.newArrayListWithCapacity(5);
-        ResultSet valRs = valStmt.executeQuery();
-        try {
+      PreparedStatement valStmt = ((JdbcSchema) db).getConnection().prepareStatement(
+              "SELECT value, name"
+                      + " FROM approval_category_values"
+                      + " WHERE category_id = ?");
+      try {
+        while (catRs.next()) {
+          String id = catRs.getString("category_id");
+          valStmt.setString(1, id);
+          List<LabelValue> values = Lists.newArrayListWithCapacity(5);
+          ResultSet valRs = valStmt.executeQuery();
           while (valRs.next()) {
             values.add(new LabelValue(
                 valRs.getShort("value"), valRs.getString("name")));
           }
-        } finally {
-          valRs.close();
+          LegacyLabelType type =
+              new LegacyLabelType(getLabelName(catRs.getString("name")), values);
+          type.setId(id);
+          type.setAbbreviation(catRs.getString("abbreviated_name"));
+          type.setFunctionName(catRs.getString("function_name"));
+          type.setCopyMinScore("Y".equals(catRs.getString("copy_min_score")));
+          types.add(type);
         }
-        LegacyLabelType type =
-            new LegacyLabelType(getLabelName(catRs.getString("name")), values);
-        type.setId(id);
-        type.setAbbreviation(catRs.getString("abbreviated_name"));
-        type.setFunctionName(catRs.getString("function_name"));
-        type.setCopyMinScore("Y".equals(catRs.getString("copy_min_score")));
-        types.add(type);
-      }
-    } finally {
-      if (valStmt != null) {
+      } finally {
         valStmt.close();
       }
-      if (catRs != null) {
-        catRs.close();
-      }
-      if (catStmt != null) {
-        catStmt.close();
-      }
+    } finally {
+      catStmt.close();
     }
     return new LegacyLabelTypes(types);
   }
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 254a780..12c80f4 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
@@ -37,7 +37,7 @@
 
   static final ScriptRunner NOOP = new ScriptRunner(null, null) {
     void run(final ReviewDb db) {
-    };
+    }
   };
 
   ScriptRunner(final String scriptName, final InputStream script) {
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 dd874b2..a2b0ad1 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
@@ -140,7 +140,7 @@
   /** A file served out of the tools root directory. */
   public static class Entry {
     public static enum Type {
-      DIR, FILE;
+      DIR, FILE
     }
 
     private final Type type;
diff --git a/gerrit-server/src/test/java/com/google/gerrit/rules/GerritCommonTest.java b/gerrit-server/src/test/java/com/google/gerrit/rules/GerritCommonTest.java
index 0d0ab1a..07e278a 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/rules/GerritCommonTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/rules/GerritCommonTest.java
@@ -29,6 +29,8 @@
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.inject.AbstractModule;
+import org.junit.Before;
+import org.junit.Test;
 
 import java.util.Arrays;
 
@@ -46,9 +48,8 @@
   private ProjectConfig local;
   private Util util;
 
-  @Override
+  @Before
   public void setUp() throws Exception {
-    super.setUp();
     util = new Util();
     load("gerrit", "gerrit_common_test.pl", new AbstractModule() {
       @Override
@@ -86,6 +87,7 @@
     env.set(StoredValues.CHANGE_CONTROL, util.user(local).controlFor(change));
   }
 
+  @Test
   public void testGerritCommon() {
     runPrologBasedTests();
   }
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 df39003..19edaf4 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
@@ -29,8 +29,6 @@
 import com.googlecode.prolog_cafe.lang.Term;
 import com.googlecode.prolog_cafe.lang.VariableTerm;
 
-import junit.framework.TestCase;
-
 import java.io.BufferedReader;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -41,9 +39,13 @@
 import java.util.Arrays;
 import java.util.List;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 
 /** Base class for any tests written in Prolog. */
-public abstract class PrologTestCase extends TestCase {
+public abstract class PrologTestCase {
   private static final SymbolTerm test_1 = SymbolTerm.intern("test", 1);
 
   private String pkg;
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/StringUtilTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/StringUtilTest.java
index 24f3386..0bbec8a 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/StringUtilTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/StringUtilTest.java
@@ -14,13 +14,16 @@
 
 package com.google.gerrit.server;
 
-import junit.framework.TestCase;
+import org.junit.Test;
 
-public class StringUtilTest extends TestCase {
+import static org.junit.Assert.assertEquals;
+
+public class StringUtilTest {
   /**
    * Test the boundary condition that the first character of a string
    * should be escaped.
    */
+  @Test
   public void testEscapeFirstChar() {
     assertEquals(StringUtil.escapeString("\tLeading tab"), "\\tLeading tab");
   }
@@ -29,6 +32,7 @@
    * Test the boundary condition that the last character of a string
    * should be escaped.
    */
+  @Test
   public void testEscapeLastChar() {
     assertEquals(StringUtil.escapeString("Trailing tab\t"), "Trailing tab\\t");
   }
@@ -37,6 +41,7 @@
    * Test that various forms of input strings are escaped (or left as-is)
    * in the expected way.
    */
+  @Test
   public void testEscapeString() {
     final String[] testPairs =
       { "", "",
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 18b3c98..d15210d 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
@@ -18,6 +18,9 @@
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.expectLastCall;
 import static org.easymock.EasyMock.replay;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
 
 import com.google.common.base.Objects;
 import com.google.common.collect.ImmutableMap;
@@ -46,9 +49,9 @@
 import com.google.inject.Injector;
 import com.google.inject.TypeLiteral;
 
-import junit.framework.TestCase;
-
 import org.easymock.IAnswer;
+import org.junit.Before;
+import org.junit.Test;
 
 import java.sql.Timestamp;
 import java.util.ArrayList;
@@ -56,7 +59,7 @@
 import java.util.List;
 import java.util.Map;
 
-public class CommentsTest extends TestCase {
+public class CommentsTest {
 
   private Injector injector;
   private RevisionResource revRes1;
@@ -65,8 +68,8 @@
   private PatchLineComment plc2;
   private PatchLineComment plc3;
 
-  @Override
-  protected void setUp() throws Exception {
+  @Before
+  public void setUp() throws Exception {
     @SuppressWarnings("unchecked")
     final DynamicMap<RestView<CommentResource>> views =
         createMock(DynamicMap.class);
@@ -130,6 +133,7 @@
     injector = Guice.createInjector(mod);
   }
 
+  @Test
   public void testListComments() throws Exception {
     // test ListComments for patch set 1
     assertListComments(injector, revRes1, ImmutableMap.of(
@@ -140,6 +144,7 @@
         Collections.<String, ArrayList<PatchLineComment>>emptyMap());
   }
 
+  @Test
   public void testGetComment() throws Exception {
     // test GetComment for existing comment
     assertGetComment(injector, revRes1, plc1, plc1.getKey().get());
@@ -186,9 +191,9 @@
     assertNotNull(actual);
     assertEquals(expected.size(), actual.size());
     assertEquals(expected.keySet(), actual.keySet());
-    for (String filename : expected.keySet()) {
-      List<PatchLineComment> expectedComments = expected.get(filename);
-      List<CommentInfo> actualComments = actual.get(filename);
+    for (Map.Entry<String, ArrayList<PatchLineComment>> entry : expected.entrySet()) {
+      List<PatchLineComment> expectedComments = entry.getValue();
+      List<CommentInfo> actualComments = actual.get(entry.getKey());
       assertNotNull(actualComments);
       assertEquals(expectedComments.size(), actualComments.size());
       for (int i = 0; i < expectedComments.size(); i++) {
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/config/ConfigUtilTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/config/ConfigUtilTest.java
index 5d72916..cc19811 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/config/ConfigUtilTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/config/ConfigUtilTest.java
@@ -14,17 +14,19 @@
 
 package com.google.gerrit.server.config;
 
+import org.junit.Test;
+
 import static java.util.concurrent.TimeUnit.DAYS;
 import static java.util.concurrent.TimeUnit.HOURS;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.MINUTES;
 import static java.util.concurrent.TimeUnit.SECONDS;
-
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
 
 import java.util.concurrent.TimeUnit;
 
-public class ConfigUtilTest extends TestCase {
+public class ConfigUtilTest {
+  @Test
   public void testTimeUnit() {
     assertEquals(ms(0, MILLISECONDS), parse("0"));
     assertEquals(ms(2, MILLISECONDS), parse("2ms"));
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/config/SitePathsTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/config/SitePathsTest.java
index 0087df6..5fdecf0 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/config/SitePathsTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/config/SitePathsTest.java
@@ -14,15 +14,23 @@
 
 package com.google.gerrit.server.config;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 import com.google.gerrit.server.util.HostPlatform;
 
-import junit.framework.TestCase;
+import org.junit.Test;
 
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 
-public class SitePathsTest extends TestCase {
+public class SitePathsTest {
+  @Test
   public void testCreate_NotExisting() throws IOException {
     final File root = random();
     final SitePaths site = new SitePaths(root);
@@ -31,6 +39,7 @@
     assertEquals(new File(root, "etc"), site.etc_dir);
   }
 
+  @Test
   public void testCreate_Empty() throws IOException {
     final File root = random();
     try {
@@ -44,6 +53,7 @@
     }
   }
 
+  @Test
   public void testCreate_NonEmpty() throws IOException {
     final File root = random();
     final File txt = new File(root, "test.txt");
@@ -60,6 +70,7 @@
     }
   }
 
+  @Test
   public void testCreate_NotDirectory() throws IOException {
     final File root = random();
     try {
@@ -75,6 +86,7 @@
     }
   }
 
+  @Test
   public void testResolve() throws IOException {
     final File root = random();
     final SitePaths site = new SitePaths(root);
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/index/IndexRewriteTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/index/IndexRewriteTest.java
index d9016e9..f9eb18f 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/index/IndexRewriteTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/index/IndexRewriteTest.java
@@ -19,6 +19,9 @@
 import static com.google.gerrit.reviewdb.client.Change.Status.MERGED;
 import static com.google.gerrit.reviewdb.client.Change.Status.NEW;
 import static com.google.gerrit.reviewdb.client.Change.Status.SUBMITTED;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 
 import com.google.common.collect.ImmutableList;
 import com.google.gerrit.reviewdb.client.Change;
@@ -31,22 +34,21 @@
 import com.google.gerrit.server.query.change.ChangeQueryBuilder;
 import com.google.gerrit.server.query.change.OrSource;
 import com.google.gerrit.server.query.change.SqlRewriterImpl;
-
-import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
 
 import java.util.EnumSet;
 import java.util.Set;
 
 @SuppressWarnings("unchecked")
-public class IndexRewriteTest extends TestCase {
+public class IndexRewriteTest {
   private FakeIndex index;
   private IndexCollection indexes;
   private ChangeQueryBuilder queryBuilder;
   private IndexRewriteImpl rewrite;
 
-  @Override
+  @Before
   public void setUp() throws Exception {
-    super.setUp();
     index = new FakeIndex(FakeIndex.V2);
     indexes = new IndexCollection();
     indexes.setSearchIndex(index);
@@ -58,26 +60,31 @@
         new SqlRewriterImpl(null));
   }
 
+  @Test
   public void testIndexPredicate() throws Exception {
     Predicate<ChangeData> in = parse("file:a");
     assertEquals(query(in), rewrite(in));
   }
 
+  @Test
   public void testNonIndexPredicate() throws Exception {
     Predicate<ChangeData> in = parse("foo:a");
     assertSame(in, rewrite(in));
   }
 
+  @Test
   public void testIndexPredicates() throws Exception {
     Predicate<ChangeData> in = parse("file:a file:b");
     assertEquals(query(in), rewrite(in));
   }
 
+  @Test
   public void testNonIndexPredicates() throws Exception {
     Predicate<ChangeData> in = parse("foo:a OR foo:b");
     assertEquals(in, rewrite(in));
   }
 
+  @Test
   public void testOneIndexPredicate() throws Exception {
     Predicate<ChangeData> in = parse("foo:a file:b");
     Predicate<ChangeData> out = rewrite(in);
@@ -87,6 +94,7 @@
         out.getChildren());
   }
 
+  @Test
   public void testThreeLevelTreeWithAllIndexPredicates() throws Exception {
     Predicate<ChangeData> in =
         parse("-status:abandoned (status:open OR status:merged)");
@@ -95,6 +103,7 @@
         rewrite.rewrite(in));
   }
 
+  @Test
   public void testThreeLevelTreeWithSomeIndexPredicates() throws Exception {
     Predicate<ChangeData> in = parse("-foo:a (file:b OR file:c)");
     Predicate<ChangeData> out = rewrite(in);
@@ -104,6 +113,7 @@
         out.getChildren());
   }
 
+  @Test
   public void testMultipleIndexPredicates() throws Exception {
     Predicate<ChangeData> in =
         parse("file:a OR foo:b OR file:c OR foo:d");
@@ -115,6 +125,7 @@
         out.getChildren());
   }
 
+  @Test
   public void testIndexAndNonIndexPredicates() throws Exception {
     Predicate<ChangeData> in = parse("status:new bar:p file:a");
     Predicate<ChangeData> out = rewrite(in);
@@ -125,6 +136,7 @@
         out.getChildren());
   }
 
+  @Test
   public void testDuplicateCompoundNonIndexOnlyPredicates() throws Exception {
     Predicate<ChangeData> in =
         parse("(status:new OR status:draft) bar:p file:a");
@@ -136,6 +148,7 @@
         out.getChildren());
   }
 
+  @Test
   public void testDuplicateCompoundIndexOnlyPredicates() throws Exception {
     Predicate<ChangeData> in =
         parse("(status:new OR file:a) bar:p file:b");
@@ -147,6 +160,7 @@
         out.getChildren());
   }
 
+  @Test
   public void testLimit() throws Exception {
     Predicate<ChangeData> in = parse("file:a limit:3");
     Predicate<ChangeData> out = rewrite(in);
@@ -157,6 +171,7 @@
         out.getChildren());
   }
 
+  @Test
   public void testGetPossibleStatus() throws Exception {
     assertEquals(EnumSet.allOf(Change.Status.class), status("file:a"));
     assertEquals(EnumSet.of(NEW), status("is:new"));
@@ -173,6 +188,7 @@
         status("(is:new is:draft) OR (is:merged OR is:submitted)"));
   }
 
+  @Test
   public void testUnsupportedIndexOperator() throws Exception {
     Predicate<ChangeData> in = parse("status:merged file:a");
     assertEquals(query(in), rewrite(in));
@@ -186,6 +202,7 @@
         out.getChildren());
   }
 
+  @Test
   public void testNoChangeIndexUsesSqlRewrites() throws Exception {
     Predicate<ChangeData> in = parse("status:open project:p ref:b");
     Predicate<ChangeData> out;
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/index/IndexedChangeQueryTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/index/IndexedChangeQueryTest.java
index 81518f5..3d21902 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/index/IndexedChangeQueryTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/index/IndexedChangeQueryTest.java
@@ -15,32 +15,35 @@
 package com.google.gerrit.server.index;
 
 import static com.google.gerrit.server.index.IndexedChangeQuery.replaceSortKeyPredicates;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
 
 import com.google.gerrit.server.query.Predicate;
 import com.google.gerrit.server.query.QueryParseException;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gerrit.server.query.change.ChangeQueryBuilder;
+import org.junit.Before;
+import org.junit.Test;
 
-import junit.framework.TestCase;
-
-public class IndexedChangeQueryTest extends TestCase {
+public class IndexedChangeQueryTest {
   private FakeIndex index;
   private ChangeQueryBuilder queryBuilder;
 
-  @Override
+  @Before
   public void setUp() throws Exception {
-    super.setUp();
     index = new FakeIndex(FakeIndex.V2);
     IndexCollection indexes = new IndexCollection();
     indexes.setSearchIndex(index);
     queryBuilder = new FakeQueryBuilder(indexes);
   }
 
+  @Test
   public void testReplaceSortKeyPredicate_NoSortKey() throws Exception {
     Predicate<ChangeData> p = parse("foo:a bar:b OR (foo:b bar:a)");
     assertSame(p, replaceSortKeyPredicates(p, "1234"));
   }
 
+  @Test
   public void testReplaceSortKeyPredicate_TopLevelSortKey() throws Exception {
     Predicate<ChangeData> p;
     p = parse("foo:a bar:b sortkey_before:1234 OR (foo:b bar:a)");
@@ -51,6 +54,7 @@
         replaceSortKeyPredicates(p, "5678"));
   }
 
+  @Test
   public void testReplaceSortKeyPredicate_NestedSortKey() throws Exception {
     Predicate<ChangeData> p;
     p = parse("foo:a bar:b OR (foo:b bar:a AND sortkey_before:1234)");
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/ioutil/BasicSerializationTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/ioutil/BasicSerializationTest.java
index 9b6b0df..622b31e 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/ioutil/BasicSerializationTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/ioutil/BasicSerializationTest.java
@@ -14,27 +14,31 @@
 
 package com.google.gerrit.server.ioutil;
 
+import org.junit.Test;
+
 import static com.google.gerrit.server.ioutil.BasicSerialization.readFixInt64;
 import static com.google.gerrit.server.ioutil.BasicSerialization.readString;
 import static com.google.gerrit.server.ioutil.BasicSerialization.readVarInt32;
 import static com.google.gerrit.server.ioutil.BasicSerialization.writeFixInt64;
 import static com.google.gerrit.server.ioutil.BasicSerialization.writeString;
 import static com.google.gerrit.server.ioutil.BasicSerialization.writeVarInt32;
-
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 
-public class BasicSerializationTest extends TestCase {
+public class BasicSerializationTest {
+  @Test
   public void testReadVarInt32() throws IOException {
     assertEquals(0x00000000, readVarInt32(r(b(0))));
     assertEquals(0x00000003, readVarInt32(r(b(3))));
     assertEquals(0x000000ff, readVarInt32(r(b(0x80 | 0x7f, 0x01))));
   }
 
+  @Test
   public void testWriteVarInt32() throws IOException {
     ByteArrayOutputStream out;
 
@@ -51,6 +55,7 @@
     assertOutput(b(0x80 | 0x7f, 0x01), out);
   }
 
+  @Test
   public void testReadFixInt64() throws IOException {
     assertEquals(0L, readFixInt64(r(b(0, 0, 0, 0, 0, 0, 0, 0))));
     assertEquals(3L, readFixInt64(r(b(0, 0, 0, 0, 0, 0, 0, 3))));
@@ -71,6 +76,7 @@
         0xff, 0xff, 0xff, 0xff))));
   }
 
+  @Test
   public void testWriteFixInt64() throws IOException {
     ByteArrayOutputStream out;
 
@@ -99,6 +105,7 @@
     assertOutput(b(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff), out);
   }
 
+  @Test
   public void testReadString() throws IOException {
     assertNull(readString(r(b(0))));
     assertEquals("a", readString(r(b(1, 'a'))));
@@ -106,6 +113,7 @@
         readString(r(b(7, 'c', 'o', 'f', 'f', 'e', 'e', '4'))));
   }
 
+  @Test
   public void testWriteString() throws IOException {
     ByteArrayOutputStream out;
 
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/ioutil/ColumnFormatterTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/ioutil/ColumnFormatterTest.java
index 2d432e6..02d0582 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/ioutil/ColumnFormatterTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/ioutil/ColumnFormatterTest.java
@@ -14,14 +14,13 @@
 
 package com.google.gerrit.server.ioutil;
 
-import com.google.gerrit.server.ioutil.ColumnFormatter;
-
-import junit.framework.TestCase;
+import org.junit.Assert;
+import org.junit.Test;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
 
-public class ColumnFormatterTest extends TestCase {
+public class ColumnFormatterTest {
   /**
    * Holds an in-memory {@link java.io.PrintWriter} object and allows
    * comparisons of its contents to a supplied string via an assert statement.
@@ -37,7 +36,7 @@
 
     public void assertEquals(String str) {
       printWriter.flush();
-      TestCase.assertEquals(stringWriter.toString(), str);
+      Assert.assertEquals(stringWriter.toString(), str);
     }
 
     public PrintWriter getPrintWriter() {
@@ -48,6 +47,7 @@
   /**
    * Test that only lines with at least one column of text emit output.
    */
+  @Test
   public void testEmptyLine() {
     final PrintWriterComparator comparator = new PrintWriterComparator();
     final ColumnFormatter formatter =
@@ -66,6 +66,7 @@
   /**
    * Test that there is no output if no columns are ever added.
    */
+  @Test
   public void testEmptyOutput() {
     final PrintWriterComparator comparator = new PrintWriterComparator();
     final ColumnFormatter formatter =
@@ -80,6 +81,7 @@
    * Test that there is no output (nor any exceptions) if we finalize
    * the output immediately after the creation of the {@link ColumnFormatter}.
    */
+  @Test
   public void testNoNextLine() {
     final PrintWriterComparator comparator = new PrintWriterComparator();
     final ColumnFormatter formatter =
@@ -92,6 +94,7 @@
    * Test that the text in added columns is escaped while the column separator
    * (which of course shouldn't be escaped) is left alone.
    */
+  @Test
   public void testEscapingTakesPlace() {
     final PrintWriterComparator comparator = new PrintWriterComparator();
     final ColumnFormatter formatter =
@@ -108,6 +111,7 @@
    * Test that we get the correct output with multi-line input where the number
    * of columns in each line varies.
    */
+  @Test
   public void testMultiLineDifferentColumnCount() {
     final PrintWriterComparator comparator = new PrintWriterComparator();
     final ColumnFormatter formatter =
@@ -126,6 +130,7 @@
   /**
    * Test that we get the correct output with a single column of input.
    */
+  @Test
   public void testOneColumn() {
     final PrintWriterComparator comparator = new PrintWriterComparator();
     final ColumnFormatter formatter =
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/mail/AddressTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/mail/AddressTest.java
index fbbd72b..02ebf51 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/mail/AddressTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/mail/AddressTest.java
@@ -14,53 +14,65 @@
 
 package com.google.gerrit.server.mail;
 
-import junit.framework.TestCase;
+import org.junit.Test;
 
 import java.io.UnsupportedEncodingException;
 
-public class AddressTest extends TestCase {
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+public class AddressTest {
+  @Test
   public void testParse_NameEmail1() {
     final Address a = Address.parse("A U Thor <author@example.com>");
     assertEquals("A U Thor", a.name);
     assertEquals("author@example.com", a.email);
   }
 
+  @Test
   public void testParse_NameEmail2() {
     final Address a = Address.parse("A <a@b>");
     assertEquals("A", a.name);
     assertEquals("a@b", a.email);
   }
 
+  @Test
   public void testParse_NameEmail3() {
     final Address a = Address.parse("<a@b>");
     assertNull(a.name);
     assertEquals("a@b", a.email);
   }
 
+  @Test
   public void testParse_NameEmail4() {
     final Address a = Address.parse("A U Thor<author@example.com>");
     assertEquals("A U Thor", a.name);
     assertEquals("author@example.com", a.email);
   }
 
+  @Test
   public void testParse_NameEmail5() {
     final Address a = Address.parse("A U Thor  <author@example.com>");
     assertEquals("A U Thor", a.name);
     assertEquals("author@example.com", a.email);
   }
 
+  @Test
   public void testParse_Email1() {
     final Address a = Address.parse("author@example.com");
     assertNull(a.name);
     assertEquals("author@example.com", a.email);
   }
 
+  @Test
   public void testParse_Email2() {
     final Address a = Address.parse("a@b");
     assertNull(a.name);
     assertEquals("a@b", a.email);
   }
 
+  @Test
   public void testParseInvalid() {
     assertInvalid("");
     assertInvalid("a");
@@ -88,34 +100,42 @@
     }
   }
 
+  @Test
   public void testToHeaderString_NameEmail1() {
     assertEquals("A <a@a>", format("A", "a@a"));
   }
 
+  @Test
   public void testToHeaderString_NameEmail2() {
     assertEquals("A B <a@a>", format("A B", "a@a"));
   }
 
+  @Test
   public void testToHeaderString_NameEmail3() {
     assertEquals("\"A B. C\" <a@a>", format("A B. C", "a@a"));
   }
 
+  @Test
   public void testToHeaderString_NameEmail4() {
     assertEquals("\"A B, C\" <a@a>", format("A B, C", "a@a"));
   }
 
+  @Test
   public void testToHeaderString_NameEmail5() {
     assertEquals("\"A \\\" C\" <a@a>", format("A \" C", "a@a"));
   }
 
+  @Test
   public void testToHeaderString_NameEmail6() {
     assertEquals("=?UTF-8?Q?A_=E2=82=AC_B?= <a@a>", format("A \u20ac B", "a@a"));
   }
 
+  @Test
   public void testToHeaderString_Email1() {
     assertEquals("a@a", format(null, "a@a"));
   }
 
+  @Test
   public void testToHeaderString_Email2() {
     assertEquals("<a,b@a>", format(null, "a,b@a"));
   }
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/mail/FromAddressGeneratorProviderTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/mail/FromAddressGeneratorProviderTest.java
index 721059c..af31eaf 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/mail/FromAddressGeneratorProviderTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/mail/FromAddressGeneratorProviderTest.java
@@ -19,6 +19,9 @@
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.AccountExternalId;
@@ -27,21 +30,20 @@
 import com.google.gerrit.server.account.AccountState;
 import com.google.gerrit.server.util.TimeUtil;
 
-import junit.framework.TestCase;
-
 import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.PersonIdent;
+import org.junit.Before;
+import org.junit.Test;
 
 import java.util.Collections;
 
-public class FromAddressGeneratorProviderTest extends TestCase {
+public class FromAddressGeneratorProviderTest {
   private Config config;
   private PersonIdent ident;
   private AccountCache accountCache;
 
-  @Override
-  protected void setUp() throws Exception {
-    super.setUp();
+  @Before
+  public void setUp() throws Exception {
     config = new Config();
     ident = new PersonIdent("NAME", "e@email", 0, 0);
     accountCache = createStrictMock(AccountCache.class);
@@ -56,10 +58,12 @@
     config.setString("sendemail", null, "from", newFrom);
   }
 
+  @Test
   public void testDefaultIsMIXED() {
     assertTrue(create() instanceof FromAddressGeneratorProvider.PatternGen);
   }
 
+  @Test
   public void testSelectUSER() {
     setFrom("USER");
     assertTrue(create() instanceof FromAddressGeneratorProvider.UserGen);
@@ -71,6 +75,7 @@
     assertTrue(create() instanceof FromAddressGeneratorProvider.UserGen);
   }
 
+  @Test
   public void testUSER_FullyConfiguredUser() {
     setFrom("USER");
 
@@ -86,6 +91,7 @@
     verify(accountCache);
   }
 
+  @Test
   public void testUSER_NoFullNameUser() {
     setFrom("USER");
 
@@ -100,6 +106,7 @@
     verify(accountCache);
   }
 
+  @Test
   public void testUSER_NoPreferredEmailUser() {
     setFrom("USER");
 
@@ -114,6 +121,7 @@
     verify(accountCache);
   }
 
+  @Test
   public void testUSER_NullUser() {
     setFrom("USER");
     replay(accountCache);
@@ -124,6 +132,7 @@
     verify(accountCache);
   }
 
+  @Test
   public void testSelectSERVER() {
     setFrom("SERVER");
     assertTrue(create() instanceof FromAddressGeneratorProvider.ServerGen);
@@ -135,6 +144,7 @@
     assertTrue(create() instanceof FromAddressGeneratorProvider.ServerGen);
   }
 
+  @Test
   public void testSERVER_FullyConfiguredUser() {
     setFrom("SERVER");
 
@@ -150,6 +160,7 @@
     verify(accountCache);
   }
 
+  @Test
   public void testSERVER_NullUser() {
     setFrom("SERVER");
     replay(accountCache);
@@ -160,6 +171,7 @@
     verify(accountCache);
   }
 
+  @Test
   public void testSelectMIXED() {
     setFrom("MIXED");
     assertTrue(create() instanceof FromAddressGeneratorProvider.PatternGen);
@@ -171,6 +183,7 @@
     assertTrue(create() instanceof FromAddressGeneratorProvider.PatternGen);
   }
 
+  @Test
   public void testMIXED_FullyConfiguredUser() {
     setFrom("MIXED");
 
@@ -186,6 +199,7 @@
     verify(accountCache);
   }
 
+  @Test
   public void testMIXED_NoFullNameUser() {
     setFrom("MIXED");
 
@@ -200,6 +214,7 @@
     verify(accountCache);
   }
 
+  @Test
   public void testMIXED_NoPreferredEmailUser() {
     setFrom("MIXED");
 
@@ -214,6 +229,7 @@
     verify(accountCache);
   }
 
+  @Test
   public void testMIXED_NullUser() {
     setFrom("MIXED");
     replay(accountCache);
@@ -224,6 +240,7 @@
     verify(accountCache);
   }
 
+  @Test
   public void testCUSTOM_FullyConfiguredUser() {
     setFrom("A ${user} B <my.server@email.address>");
 
@@ -239,6 +256,7 @@
     verify(accountCache);
   }
 
+  @Test
   public void testCUSTOM_NoFullNameUser() {
     setFrom("A ${user} B <my.server@email.address>");
 
@@ -253,6 +271,7 @@
     verify(accountCache);
   }
 
+  @Test
   public void testCUSTOM_NullUser() {
     setFrom("A ${user} B <my.server@email.address>");
 
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/patch/PatchListEntryTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/patch/PatchListEntryTest.java
index 7df0696..af60ea8 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/patch/PatchListEntryTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/patch/PatchListEntryTest.java
@@ -12,14 +12,18 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-
 package com.google.gerrit.server.patch;
 
 import com.google.gerrit.reviewdb.client.Patch;
+import org.junit.Test;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 
-public class PatchListEntryTest extends TestCase {
+public class PatchListEntryTest {
+  @Test
   public void testEmpty1() {
     final String name = "empty-file";
     final PatchListEntry e = PatchListEntry.empty(name);
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java
index 8f4e058..79929fc 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java
@@ -26,6 +26,8 @@
 import static com.google.gerrit.server.project.Util.DEVS;
 import static com.google.gerrit.server.project.Util.grant;
 import static com.google.gerrit.server.project.Util.doNotInherit;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import com.google.gerrit.common.data.Capable;
 import com.google.gerrit.common.data.PermissionRange;
@@ -33,10 +35,10 @@
 import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.git.ProjectConfig;
+import org.junit.Before;
+import org.junit.Test;
 
-import junit.framework.TestCase;
-
-public class RefControlTest extends TestCase {
+public class RefControlTest {
   private static void assertOwner(String ref, ProjectControl u) {
     assertTrue("OWN " + ref, u.controlForRef(ref).isOwner());
   }
@@ -54,14 +56,14 @@
     util = new Util();
   }
 
-  @Override
+  @Before
   public void setUp() throws Exception {
-    super.setUp();
     local = new ProjectConfig(localKey);
     local.createInMemory();
     util.add(local);
   }
 
+  @Test
   public void testOwnerProject() {
     grant(local, OWNER, ADMIN, "refs/*");
 
@@ -72,6 +74,7 @@
     assertTrue("is owner", uAdmin.isOwner());
   }
 
+  @Test
   public void testBranchDelegation1() {
     grant(local, OWNER, ADMIN, "refs/*");
     grant(local, OWNER, DEVS, "refs/heads/x/*");
@@ -88,6 +91,7 @@
     assertNotOwner("refs/heads/master", uDev);
   }
 
+  @Test
   public void testBranchDelegation2() {
     grant(local, OWNER, ADMIN, "refs/*");
     grant(local, OWNER, DEVS, "refs/heads/x/*");
@@ -116,6 +120,7 @@
     assertNotOwner("refs/heads/master", uFix);
   }
 
+  @Test
   public void testInheritRead_SingleBranchDeniesUpload() {
     grant(util.getParentConfig(), READ, REGISTERED, "refs/*");
     grant(util.getParentConfig(), PUSH, REGISTERED, "refs/for/refs/*");
@@ -133,6 +138,7 @@
         u.controlForRef("refs/heads/foobar").canUpload());
   }
 
+  @Test
   public void testInheritRead_SingleBranchDoesNotOverrideInherited() {
     grant(util.getParentConfig(), READ, REGISTERED, "refs/*");
     grant(util.getParentConfig(), PUSH, REGISTERED, "refs/for/refs/*");
@@ -148,6 +154,7 @@
         u.controlForRef("refs/heads/foobar").canUpload());
   }
 
+  @Test
   public void testInheritDuplicateSections() {
     grant(util.getParentConfig(), READ, ADMIN, "refs/*");
     grant(local, READ, DEVS, "refs/heads/*");
@@ -160,6 +167,7 @@
     assertTrue("d can read", util.user(local, "d", DEVS).isVisible());
   }
 
+  @Test
   public void testInheritRead_OverrideWithDeny() {
     grant(util.getParentConfig(), READ, REGISTERED, "refs/*");
     grant(local, READ, REGISTERED, "refs/*").setDeny();
@@ -168,6 +176,7 @@
     assertFalse("can't read", u.isVisible());
   }
 
+  @Test
   public void testInheritRead_AppendWithDenyOfRef() {
     grant(util.getParentConfig(), READ, REGISTERED, "refs/*");
     grant(local, READ, REGISTERED, "refs/heads/*").setDeny();
@@ -179,6 +188,7 @@
     assertTrue("no master", u.controlForRef("refs/heads/master").isVisible());
   }
 
+  @Test
   public void testInheritRead_OverridesAndDeniesOfRef() {
     grant(util.getParentConfig(), READ, REGISTERED, "refs/*");
     grant(local, READ, REGISTERED, "refs/*").setDeny();
@@ -191,6 +201,7 @@
     assertTrue("can read", u.controlForRef("refs/heads/foobar").isVisible());
   }
 
+  @Test
   public void testInheritSubmit_OverridesAndDeniesOfRef() {
     grant(util.getParentConfig(), SUBMIT, REGISTERED, "refs/*");
     grant(local, SUBMIT, REGISTERED, "refs/*").setDeny();
@@ -202,6 +213,7 @@
     assertTrue("can submit", u.controlForRef("refs/heads/foobar").canSubmit());
   }
 
+  @Test
   public void testCannotUploadToAnyRef() {
     grant(util.getParentConfig(), READ, REGISTERED, "refs/*");
     grant(local, READ, DEVS, "refs/heads/*");
@@ -213,6 +225,7 @@
         u.controlForRef("refs/heads/master").canUpload());
   }
 
+  @Test
   public void testUsernamePatternNonRegex() {
     grant(local, READ, DEVS, "refs/sb/${username}/heads/*");
 
@@ -221,6 +234,7 @@
     assertTrue("d can read", d.controlForRef("refs/sb/d/heads/foobar").isVisible());
   }
 
+  @Test
   public void testUsernamePatternWithRegex() {
     grant(local, READ, DEVS, "^refs/sb/${username}/heads/.*");
 
@@ -229,6 +243,7 @@
     assertTrue("d can read", d.controlForRef("refs/sb/dev/heads/foobar").isVisible());
   }
 
+  @Test
   public void testSortWithRegex() {
     grant(local, READ, DEVS, "^refs/heads/.*");
     grant(util.getParentConfig(), READ, ANONYMOUS, "^refs/heads/.*-QA-.*");
@@ -238,6 +253,7 @@
     assertTrue("d can read", d.controlForRef("refs/heads/foo-QA-bar").isVisible());
   }
 
+  @Test
   public void testBlockRule_ParentBlocksChild() {
     grant(local, PUSH, DEVS, "refs/tags/*");
     grant(util.getParentConfig(), PUSH, ANONYMOUS, "refs/tags/*").setBlock();
@@ -246,6 +262,7 @@
     assertFalse("u can't force update tag", u.controlForRef("refs/tags/V10").canForceUpdate());
   }
 
+  @Test
   public void testBlockLabelRange_ParentBlocksChild() {
     grant(local, LABEL + "Code-Review", -2, +2, DEVS, "refs/heads/*");
     grant(util.getParentConfig(), LABEL + "Code-Review", -2, +2, DEVS, "refs/heads/*").setBlock();
@@ -259,6 +276,7 @@
     assertFalse("u can't vote 2", range.contains(2));
   }
 
+  @Test
   public void testUnblockNoForce() {
     grant(local, PUSH, ANONYMOUS, "refs/heads/*").setBlock();
     grant(local, PUSH, DEVS, "refs/heads/*");
@@ -267,6 +285,7 @@
     assertTrue("u can push", u.controlForRef("refs/heads/master").canUpdate());
   }
 
+  @Test
   public void testUnblockForce() {
     PermissionRule r = grant(local, PUSH, ANONYMOUS, "refs/heads/*");
     r.setBlock();
@@ -277,6 +296,7 @@
     assertTrue("u can force push", u.controlForRef("refs/heads/master").canForceUpdate());
   }
 
+  @Test
   public void testUnblockForceWithAllowNoForce_NotPossible() {
     PermissionRule r = grant(local, PUSH, ANONYMOUS, "refs/heads/*");
     r.setBlock();
@@ -287,6 +307,7 @@
     assertFalse("u can't force push", u.controlForRef("refs/heads/master").canForceUpdate());
   }
 
+  @Test
   public void testUnblockMoreSpecificRef_Fails() {
     grant(local, PUSH, ANONYMOUS, "refs/heads/*").setBlock();
     grant(local, PUSH, DEVS, "refs/heads/master");
@@ -295,6 +316,7 @@
     assertFalse("u can't push", u.controlForRef("refs/heads/master").canUpdate());
   }
 
+  @Test
   public void testUnblockLargerScope_Fails() {
     grant(local, PUSH, ANONYMOUS, "refs/heads/master").setBlock();
     grant(local, PUSH, DEVS, "refs/heads/*");
@@ -303,6 +325,7 @@
     assertFalse("u can't push", u.controlForRef("refs/heads/master").canUpdate());
   }
 
+  @Test
   public void testUnblockInLocal_Fails() {
     grant(util.getParentConfig(), PUSH, ANONYMOUS, "refs/heads/*").setBlock();
     grant(local, PUSH, fixers, "refs/heads/*");
@@ -311,6 +334,7 @@
     assertFalse("u can't push", f.controlForRef("refs/heads/master").canUpdate());
   }
 
+  @Test
   public void testUnblockInParentBlockInLocal() {
     grant(util.getParentConfig(), PUSH, ANONYMOUS, "refs/heads/*").setBlock();
     grant(util.getParentConfig(), PUSH, DEVS, "refs/heads/*");
@@ -320,6 +344,7 @@
     assertFalse("u can't push", d.controlForRef("refs/heads/master").canUpdate());
   }
 
+  @Test
   public void testUnblockVisibilityByREGISTEREDUsers() {
     grant(local, READ, ANONYMOUS, "refs/heads/*").setBlock();
     grant(local, READ, REGISTERED, "refs/heads/*");
@@ -328,6 +353,7 @@
     assertTrue("u can read", u.controlForRef("refs/heads/master").isVisibleByRegisteredUsers());
   }
 
+  @Test
   public void testUnblockInLocalVisibilityByRegisteredUsers_Fails() {
     grant(util.getParentConfig(), READ, ANONYMOUS, "refs/heads/*").setBlock();
     grant(local, READ, REGISTERED, "refs/heads/*");
@@ -336,6 +362,7 @@
     assertFalse("u can't read", u.controlForRef("refs/heads/master").isVisibleByRegisteredUsers());
   }
 
+  @Test
   public void testUnblockForceEditTopicName() {
     grant(local, EDIT_TOPIC_NAME, ANONYMOUS, "refs/heads/*").setBlock();
     grant(local, EDIT_TOPIC_NAME, DEVS, "refs/heads/*").setForce(true);
@@ -345,6 +372,7 @@
         .canForceEditTopicName());
   }
 
+  @Test
   public void testUnblockInLocalForceEditTopicName_Fails() {
     grant(util.getParentConfig(), EDIT_TOPIC_NAME, ANONYMOUS, "refs/heads/*")
         .setBlock();
@@ -355,6 +383,7 @@
         .canForceEditTopicName());
   }
 
+  @Test
   public void testUnblockRange() {
     grant(local, LABEL + "Code-Review", -1, +1, ANONYMOUS, "refs/heads/*").setBlock();
     grant(local, LABEL + "Code-Review", -2, +2, DEVS, "refs/heads/*");
@@ -365,6 +394,7 @@
     assertTrue("u can vote +2", range.contains(2));
   }
 
+  @Test
   public void testUnblockRangeOnMoreSpecificRef_Fails() {
     grant(local, LABEL + "Code-Review", -1, +1, ANONYMOUS, "refs/heads/*").setBlock();
     grant(local, LABEL + "Code-Review", -2, +2, DEVS, "refs/heads/master");
@@ -375,6 +405,7 @@
     assertFalse("u can't vote +2", range.contains(-2));
   }
 
+  @Test
   public void testUnblockRangeOnLargerScope_Fails() {
     grant(local, LABEL + "Code-Review", -1, +1, ANONYMOUS, "refs/heads/master").setBlock();
     grant(local, LABEL + "Code-Review", -2, +2, DEVS, "refs/heads/*");
@@ -385,6 +416,7 @@
     assertFalse("u can't vote +2", range.contains(-2));
   }
 
+  @Test
   public void testUnblockInLocalRange_Fails() {
     grant(util.getParentConfig(), LABEL + "Code-Review", -1, 1, ANONYMOUS,
         "refs/heads/*").setBlock();
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 a99eba1..c6e621a 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
@@ -54,12 +54,12 @@
 import java.util.Set;
 
 public class Util {
-  public static AccountGroup.UUID ANONYMOUS = AccountGroup.ANONYMOUS_USERS;
-  public static AccountGroup.UUID REGISTERED = AccountGroup.REGISTERED_USERS;
-  public static AccountGroup.UUID ADMIN = new AccountGroup.UUID("test.admin");
-  public static AccountGroup.UUID DEVS = new AccountGroup.UUID("test.devs");
+  public static final AccountGroup.UUID ANONYMOUS = AccountGroup.ANONYMOUS_USERS;
+  public static final AccountGroup.UUID REGISTERED = AccountGroup.REGISTERED_USERS;
+  public static final AccountGroup.UUID ADMIN = new AccountGroup.UUID("test.admin");
+  public static final AccountGroup.UUID DEVS = new AccountGroup.UUID("test.devs");
 
-  public static LabelType CR = category("Code-Review",
+  public static final LabelType CR = category("Code-Review",
       value(2, "Looks good to me, approved"),
       value(1, "Looks good to me, but someone else must approve"),
       value(0, "No score"),
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/query/AndPredicateTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/query/AndPredicateTest.java
index 0ec23d5..9b3a331 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/query/AndPredicateTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/query/AndPredicateTest.java
@@ -15,14 +15,19 @@
 package com.google.gerrit.server.query;
 
 import static com.google.gerrit.server.query.Predicate.and;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 
-import junit.framework.TestCase;
+import org.junit.Test;
 
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
-public class AndPredicateTest extends TestCase {
+public class AndPredicateTest {
   private static final class TestPredicate extends OperatorPredicate<String> {
     private TestPredicate(String name, String value) {
       super(name, value);
@@ -43,6 +48,7 @@
     return new TestPredicate(name, value);
   }
 
+  @Test
   @SuppressWarnings("unchecked")
   public void testChildren() {
     final TestPredicate a = f("author", "alice");
@@ -53,6 +59,7 @@
     assertSame(b, n.getChild(1));
   }
 
+  @Test
   @SuppressWarnings("unchecked")
   public void testChildrenUnmodifiable() {
     final TestPredicate a = f("author", "alice");
@@ -83,6 +90,7 @@
     assertEquals(o + " did not affect child", l, p.getChildren());
   }
 
+  @Test
   @SuppressWarnings("unchecked")
   public void testToString() {
     final TestPredicate a = f("q", "alice");
@@ -92,6 +100,7 @@
     assertEquals("(q:alice q:bob q:charlie)", and(a, b, c).toString());
   }
 
+  @Test
   @SuppressWarnings("unchecked")
   public void testEquals() {
     final TestPredicate a = f("author", "alice");
@@ -107,6 +116,7 @@
     assertFalse(and(a, c).equals(a));
   }
 
+  @Test
   @SuppressWarnings("unchecked")
   public void testHashCode() {
     final TestPredicate a = f("author", "alice");
@@ -118,6 +128,7 @@
     assertFalse(and(a, c).hashCode() == and(a, b).hashCode());
   }
 
+  @Test
   @SuppressWarnings("unchecked")
   public void testCopy() {
     final TestPredicate a = f("author", "alice");
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/query/FieldPredicateTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/query/FieldPredicateTest.java
index a37a336..e31caaf 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/query/FieldPredicateTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/query/FieldPredicateTest.java
@@ -14,11 +14,16 @@
 
 package com.google.gerrit.server.query;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
 
 import java.util.Collections;
 
-public class FieldPredicateTest extends TestCase {
+public class FieldPredicateTest {
   private static final class TestPredicate extends OperatorPredicate<String> {
     private TestPredicate(String name, String value) {
       super(name, value);
@@ -39,12 +44,14 @@
     return new TestPredicate(name, value);
   }
 
+  @Test
   public void testToString() {
     assertEquals("author:bob", f("author", "bob").toString());
     assertEquals("author:\"\"", f("author", "").toString());
     assertEquals("owner:\"A U Thor\"", f("owner", "A U Thor").toString());
   }
 
+  @Test
   public void testEquals() {
     assertTrue(f("author", "bob").equals(f("author", "bob")));
     assertFalse(f("author", "bob").equals(f("author", "alice")));
@@ -52,11 +59,13 @@
     assertFalse(f("author", "bob").equals("author"));
   }
 
+  @Test
   public void testHashCode() {
     assertTrue(f("a", "bob").hashCode() == f("a", "bob").hashCode());
     assertFalse(f("a", "bob").hashCode() == f("a", "alice").hashCode());
   }
 
+  @Test
   public void testNameValue() {
     final String name = "author";
     final String value = "alice";
@@ -66,6 +75,7 @@
     assertEquals(0, f.getChildren().size());
   }
 
+  @Test
   public void testCopy() {
     final OperatorPredicate<String> f = f("author", "alice");
     assertSame(f, f.copy(Collections.<Predicate<String>> emptyList()));
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/query/NotPredicateTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/query/NotPredicateTest.java
index 90b9ca7..9df906c 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/query/NotPredicateTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/query/NotPredicateTest.java
@@ -16,13 +16,18 @@
 
 import static com.google.gerrit.server.query.Predicate.and;
 import static com.google.gerrit.server.query.Predicate.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 
-import junit.framework.TestCase;
+import org.junit.Test;
 
 import java.util.Collections;
 import java.util.List;
 
-public class NotPredicateTest extends TestCase {
+public class NotPredicateTest {
   private static final class TestPredicate extends OperatorPredicate<String> {
     private TestPredicate(String name, String value) {
       super(name, value);
@@ -43,6 +48,7 @@
     return new TestPredicate(name, value);
   }
 
+  @Test
   public void testNotNot() {
     final TestPredicate p = f("author", "bob");
     final Predicate<String> n = not(p);
@@ -51,6 +57,7 @@
     assertSame(p, not(n));
   }
 
+  @Test
   public void testChildren() {
     final TestPredicate p = f("author", "bob");
     final Predicate<String> n = not(p);
@@ -58,6 +65,7 @@
     assertSame(p, n.getChild(0));
   }
 
+  @Test
   public void testChildrenUnmodifiable() {
     final TestPredicate p = f("author", "bob");
     final Predicate<String> n = not(p);
@@ -87,10 +95,12 @@
     assertSame(o + " did not affect child", c, p.getChild(0));
   }
 
+  @Test
   public void testToString() {
     assertEquals("-author:bob", not(f("author", "bob")).toString());
   }
 
+  @Test
   public void testEquals() {
     assertTrue(not(f("author", "bob")).equals(not(f("author", "bob"))));
     assertFalse(not(f("author", "bob")).equals(not(f("author", "alice"))));
@@ -98,11 +108,13 @@
     assertFalse(not(f("author", "bob")).equals("author"));
   }
 
+  @Test
   public void testHashCode() {
     assertTrue(not(f("a", "b")).hashCode() == not(f("a", "b")).hashCode());
     assertFalse(not(f("a", "b")).hashCode() == not(f("a", "a")).hashCode());
   }
 
+  @Test
   @SuppressWarnings({"rawtypes", "unchecked"})
   public void testCopy() {
     final TestPredicate a = f("author", "alice");
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/query/OrPredicateTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/query/OrPredicateTest.java
index 7f3ce50..27696bb 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/query/OrPredicateTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/query/OrPredicateTest.java
@@ -15,14 +15,19 @@
 package com.google.gerrit.server.query;
 
 import static com.google.gerrit.server.query.Predicate.or;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 
-import junit.framework.TestCase;
+import org.junit.Test;
 
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
-public class OrPredicateTest extends TestCase {
+public class OrPredicateTest {
   private static final class TestPredicate extends OperatorPredicate<String> {
     private TestPredicate(String name, String value) {
       super(name, value);
@@ -43,6 +48,7 @@
     return new TestPredicate(name, value);
   }
 
+  @Test
   @SuppressWarnings("unchecked")
   public void testChildren() {
     final TestPredicate a = f("author", "alice");
@@ -53,6 +59,7 @@
     assertSame(b, n.getChild(1));
   }
 
+  @Test
   @SuppressWarnings("unchecked")
   public void testChildrenUnmodifiable() {
     final TestPredicate a = f("author", "alice");
@@ -83,6 +90,7 @@
     assertEquals(o + " did not affect child", l, p.getChildren());
   }
 
+  @Test
   @SuppressWarnings("unchecked")
   public void testToString() {
     final TestPredicate a = f("q", "alice");
@@ -92,6 +100,7 @@
     assertEquals("(q:alice OR q:bob OR q:charlie)", or(a, b, c).toString());
   }
 
+  @Test
   @SuppressWarnings("unchecked")
   public void testEquals() {
     final TestPredicate a = f("author", "alice");
@@ -107,6 +116,7 @@
     assertFalse(or(a, c).equals(a));
   }
 
+  @Test
   @SuppressWarnings("unchecked")
   public void testHashCode() {
     final TestPredicate a = f("author", "alice");
@@ -118,6 +128,7 @@
     assertFalse(or(a, c).hashCode() == or(a, b).hashCode());
   }
 
+  @Test
   @SuppressWarnings("unchecked")
   public void testCopy() {
     final TestPredicate a = f("author", "alice");
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/query/QueryParserTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/query/QueryParserTest.java
index 9534d2b..0eca069 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/query/QueryParserTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/query/QueryParserTest.java
@@ -13,13 +13,13 @@
 // limitations under the License.
 
 package com.google.gerrit.server.query;
-
-
-import junit.framework.TestCase;
-
 import org.antlr.runtime.tree.Tree;
+import org.junit.Test;
 
-public class QueryParserTest extends TestCase {
+import static org.junit.Assert.assertEquals;
+
+public class QueryParserTest {
+  @Test
   public void testProjectBare() throws QueryParseException {
     Tree r;
 
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractIndexQueryChangesTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractIndexQueryChangesTest.java
index 5dacd49..5099d10 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractIndexQueryChangesTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractIndexQueryChangesTest.java
@@ -18,10 +18,10 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.gerrit.extensions.api.changes.ReviewInput;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.change.ChangeInserter;
 import com.google.gerrit.server.change.ChangeResource;
-import com.google.gerrit.server.change.PostReview;
 import com.google.gerrit.server.change.RevisionResource;
 import com.google.gerrit.server.project.ChangeControl;
 
@@ -70,13 +70,13 @@
     Change change = ins.insert();
     ChangeControl ctl = changeControlFactory.controlFor(change, user);
 
-    PostReview.Input input = new PostReview.Input();
+    ReviewInput input = new ReviewInput();
     input.message = "toplevel";
-    PostReview.Comment comment = new PostReview.Comment();
+    ReviewInput.Comment comment = new ReviewInput.Comment();
     comment.line = 1;
     comment.message = "inline";
-    input.comments = ImmutableMap.<String, List<PostReview.Comment>> of(
-        "Foo.java", ImmutableList.<PostReview.Comment> of(comment));
+    input.comments = ImmutableMap.<String, List<ReviewInput.Comment>> of(
+        "Foo.java", ImmutableList.<ReviewInput.Comment> of(comment));
     postReview.apply(new RevisionResource(
         new ChangeResource(ctl), ins.getPatchSet()), input);
 
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
index 1e8b87a..2edb955 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
@@ -26,6 +26,7 @@
 import com.google.common.collect.Lists;
 import com.google.common.hash.Hashing;
 import com.google.gerrit.common.Nullable;
+import com.google.gerrit.extensions.api.changes.ReviewInput;
 import com.google.gerrit.extensions.restapi.TopLevelResource;
 import com.google.gerrit.lifecycle.LifecycleManager;
 import com.google.gerrit.reviewdb.client.Account;
@@ -359,7 +360,7 @@
     Change change = ins.insert();
     ChangeControl ctl = changeControlFactory.controlFor(change, user);
 
-    PostReview.Input input = new PostReview.Input();
+    ReviewInput input = new ReviewInput();
     input.message = "toplevel";
     input.labels = ImmutableMap.<String, Short> of("Code-Review", (short) 1);
     postReview.apply(new RevisionResource(
@@ -476,7 +477,7 @@
     assertResultEquals(change2, results.get(0));
     assertResultEquals(change1, results.get(1));
 
-    PostReview.Input input = new PostReview.Input();
+    ReviewInput input = new ReviewInput();
     input.message = "toplevel";
     postReview.apply(new RevisionResource(
         new ChangeResource(ctl1), ins1.getPatchSet()), input);
@@ -509,7 +510,7 @@
     assertResultEquals(change2, results.get(0));
     assertResultEquals(change1, results.get(1));
 
-    PostReview.Input input = new PostReview.Input();
+    ReviewInput input = new ReviewInput();
     input.message = "toplevel";
     postReview.apply(new RevisionResource(
         new ChangeResource(ctl1), ins1.getPatchSet()), input);
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/query/change/RegexFilePredicateTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/RegexFilePredicateTest.java
index 1500272..85b0311 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/query/change/RegexFilePredicateTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/RegexFilePredicateTest.java
@@ -16,12 +16,15 @@
 
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gwtorm.server.OrmException;
-
-import junit.framework.TestCase;
+import org.junit.Test;
 
 import java.util.Arrays;
 
-public class RegexFilePredicateTest extends TestCase {
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class RegexFilePredicateTest {
+  @Test
   public void testPrefixOnlyOptimization() throws OrmException {
     RegexFilePredicate p = predicate("^a/b/.*");
     assertTrue(p.match(change("a/b/source.c")));
@@ -31,6 +34,7 @@
     assertFalse(p.match(change("a/bb/source.c")));
   }
 
+  @Test
   public void testPrefixReducesSearchSpace() throws OrmException {
     RegexFilePredicate p = predicate("^a/b/.*\\.[ch]");
     assertTrue(p.match(change("a/b/source.c")));
@@ -40,6 +44,7 @@
     assertTrue(p.match(change("a/b/a.a", "a/b/a.d", "a/b/a.h")));
   }
 
+  @Test
   public void testFileExtension_Constant() throws OrmException {
     RegexFilePredicate p = predicate("^.*\\.res");
     assertTrue(p.match(change("test.res")));
@@ -47,6 +52,7 @@
     assertFalse(p.match(change("test.res.bar")));
   }
 
+  @Test
   public void testFileExtension_CharacterGroup() throws OrmException {
     RegexFilePredicate p = predicate("^.*\\.[ch]");
     assertTrue(p.match(change("test.c")));
@@ -54,6 +60,7 @@
     assertFalse(p.match(change("test.C")));
   }
 
+  @Test
   public void testEndOfString() throws OrmException {
     assertTrue(predicate("^a$").match(change("a")));
     assertFalse(predicate("^a$").match(change("a$")));
@@ -62,6 +69,7 @@
     assertTrue(predicate("^a\\$").match(change("a$")));
   }
 
+  @Test
   public void testExactMatch() throws OrmException {
     RegexFilePredicate p = predicate("^foo.c");
     assertTrue(p.match(change("foo.c")));
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 e58266f..4756390 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
@@ -14,6 +14,11 @@
 
 package com.google.gerrit.server.schema;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
@@ -29,9 +34,10 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 
-import junit.framework.TestCase;
-
 import org.eclipse.jgit.lib.Repository;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
 
 import java.io.File;
 import java.io.IOException;
@@ -40,7 +46,7 @@
 import java.util.Arrays;
 import java.util.List;
 
-public class SchemaCreatorTest extends TestCase {
+public class SchemaCreatorTest {
   @Inject
   private AllProjectsName allProjects;
 
@@ -50,18 +56,17 @@
   @Inject
   private InMemoryDatabase db;
 
-  @Override
-  protected void setUp() throws Exception {
-    super.setUp();
+  @Before
+  public void setUp() throws Exception {
     new InMemoryModule().inject(this);
   }
 
-  @Override
-  protected void tearDown() throws Exception {
+  @After
+  public void tearDown() throws Exception {
     InMemoryDatabase.drop(db);
-    super.tearDown();
   }
 
+  @Test
   public void testGetCauses_CreateSchema() throws OrmException, SQLException,
       IOException {
     // Initially the schema should be empty.
@@ -109,6 +114,7 @@
     }
   }
 
+  @Test
   public void testCreateSchema_LabelTypes() throws Exception {
     List<String> labels = Lists.newArrayList();
     for (LabelType label : getLabelTypes().getLabelTypes()) {
@@ -117,6 +123,7 @@
     assertEquals(ImmutableList.of("Code-Review"), labels);
   }
 
+  @Test
   public void testCreateSchema_Label_CodeReview() throws Exception {
     LabelType codeReview = getLabelTypes().byLabel("Code-Review");
     assertNotNull(codeReview);
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java
index 5039cc2..e6b7a3f 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java
@@ -34,10 +34,11 @@
 import com.google.inject.Guice;
 import com.google.inject.TypeLiteral;
 
-import junit.framework.TestCase;
-
 import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.PersonIdent;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -45,21 +46,22 @@
 import java.util.List;
 import java.util.UUID;
 
-public class SchemaUpdaterTest extends TestCase {
+import static org.junit.Assert.assertEquals;
+
+public class SchemaUpdaterTest {
   private InMemoryDatabase db;
 
-  @Override
-  protected void setUp() throws Exception {
-    super.setUp();
+  @Before
+  public void setUp() throws Exception {
     db = InMemoryDatabase.newDatabase();
   }
 
-  @Override
-  protected void tearDown() throws Exception {
+  @After
+  public void tearDown() throws Exception {
     InMemoryDatabase.drop(db);
-    super.tearDown();
   }
 
+  @Test
   public void testUpdate() throws OrmException, FileNotFoundException,
       IOException {
     db.create();
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 1f50fa2..5546410 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
@@ -14,11 +14,15 @@
 
 package com.google.gerrit.server.util;
 
-import junit.framework.TestCase;
+import org.junit.Test;
 
 import java.util.HashSet;
 
-public class IdGeneratorTest extends TestCase {
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class IdGeneratorTest {
+  @Test
   public void test1234() {
     final HashSet<Integer> seen = new HashSet<Integer>();
     for (int i = 0; i < 1 << 16; i++) {
@@ -32,6 +36,7 @@
     assertEquals(0x0b966b11, IdGenerator.unmix(IdGenerator.mix(0x0b966b11)));
   }
 
+  @Test
   public void testFormat() {
     assertEquals("0000000f", IdGenerator.format(0xf));
     assertEquals("801234ab", IdGenerator.format(0x801234ab));
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/util/SocketUtilTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/util/SocketUtilTest.java
index 9e66046..5ce8882 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/util/SocketUtilTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/util/SocketUtilTest.java
@@ -20,8 +20,12 @@
 import static com.google.gerrit.server.util.SocketUtil.resolve;
 import static java.net.InetAddress.getByName;
 import static java.net.InetSocketAddress.createUnresolved;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
-import junit.framework.TestCase;
+import org.junit.Test;
 
 import java.net.Inet4Address;
 import java.net.Inet6Address;
@@ -29,7 +33,8 @@
 import java.net.InetSocketAddress;
 import java.net.UnknownHostException;
 
-public class SocketUtilTest extends TestCase {
+public class SocketUtilTest {
+  @Test
   public void testIsIPv6() throws UnknownHostException {
     final InetAddress ipv6 = getByName("1:2:3:4:5:6:7:8");
     assertTrue(ipv6 instanceof Inet6Address);
@@ -40,12 +45,14 @@
     assertFalse(isIPv6(ipv4));
   }
 
+  @Test
   public void testHostname() {
     assertEquals("*", hostname(new InetSocketAddress(80)));
     assertEquals("localhost", hostname(new InetSocketAddress("localhost", 80)));
     assertEquals("foo", hostname(createUnresolved("foo", 80)));
   }
 
+  @Test
   public void testFormat() throws UnknownHostException {
     assertEquals("*:1234", SocketUtil.format(new InetSocketAddress(1234), 80));
     assertEquals("*", SocketUtil.format(new InetSocketAddress(80), 80));
@@ -64,6 +71,7 @@
         SocketUtil. format(new InetSocketAddress("localhost", 80), 80));
   }
 
+  @Test
   public void testParse() {
     assertEquals(new InetSocketAddress(1234), parse("*:1234", 80));
     assertEquals(new InetSocketAddress(80), parse("*", 80));
@@ -100,6 +108,7 @@
     }
   }
 
+  @Test
   public void testResolve() throws UnknownHostException {
     assertEquals(new InetSocketAddress(1234), resolve("*:1234", 80));
     assertEquals(new InetSocketAddress(80), resolve("*", 80));
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 299a245..ed86031 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
@@ -200,8 +200,9 @@
     expect(bbc.getSubsections("submodule"))
         .andReturn(sectionsToReturn.keySet());
 
-    for (final String id : sectionsToReturn.keySet()) {
-      final SubmoduleSection section = sectionsToReturn.get(id);
+    for (Map.Entry<String, SubmoduleSection> entry : sectionsToReturn.entrySet()) {
+      String id = entry.getKey();
+      final SubmoduleSection section = entry.getValue();
       expect(bbc.getString("submodule", id, "url")).andReturn(section.getUrl());
       expect(bbc.getString("submodule", id, "path")).andReturn(
           section.getPath());
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 a1e68d0..189f803 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
@@ -14,6 +14,8 @@
 
 package com.google.gerrit.testutil;
 
+import static org.junit.Assert.assertEquals;
+
 import com.google.gerrit.reviewdb.client.CurrentSchemaVersion;
 import com.google.gerrit.reviewdb.client.SystemConfig;
 import com.google.gerrit.reviewdb.server.ReviewDb;
@@ -26,8 +28,6 @@
 import com.google.inject.Guice;
 import com.google.inject.Inject;
 
-import junit.framework.TestCase;
-
 import org.eclipse.jgit.errors.ConfigInvalidException;
 
 import java.io.IOException;
@@ -162,6 +162,6 @@
 
   public void assertSchemaVersion() throws OrmException {
     final CurrentSchemaVersion act = getSchemaVersion();
-    TestCase.assertEquals(schemaVersion.getVersionNbr(), act.versionNbr);
+    assertEquals(schemaVersion.getVersionNbr(), act.versionNbr);
   }
 }
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandModule.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandModule.java
index c64f9d8..c885484 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandModule.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandModule.java
@@ -16,13 +16,13 @@
 
 import com.google.common.base.Objects;
 import com.google.common.base.Strings;
-import com.google.inject.AbstractModule;
+import com.google.gerrit.lifecycle.LifecycleModule;
 import com.google.inject.binder.LinkedBindingBuilder;
 
 import org.apache.sshd.server.Command;
 
 /** Module to register commands in the SSH daemon. */
-public abstract class CommandModule extends AbstractModule {
+public abstract class CommandModule extends LifecycleModule {
   /**
    * Configure a command to be invoked by name.
    *
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/GerritServerSession.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/GerritServerSession.java
new file mode 100644
index 0000000..b7f7c22
--- /dev/null
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/GerritServerSession.java
@@ -0,0 +1,34 @@
+// 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.sshd;
+
+import org.apache.sshd.common.future.CloseFuture;
+import org.apache.sshd.common.future.SshFutureListener;
+import org.apache.sshd.common.io.IoSession;
+import org.apache.sshd.server.ServerFactoryManager;
+import org.apache.sshd.server.session.ServerSession;
+
+/* Expose addition of close session listeners */
+class GerritServerSession extends ServerSession {
+
+  GerritServerSession(ServerFactoryManager server,
+      IoSession ioSession) throws Exception {
+    super(server, ioSession);
+  }
+
+  void addCloseSessionListener(SshFutureListener<CloseFuture> l) {
+    closeFuture.addListener(l);
+  }
+}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/NoShell.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/NoShell.java
index cde7ae8..78f006b 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/NoShell.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/NoShell.java
@@ -106,7 +106,7 @@
       } finally {
         sshScope.set(old);
       }
-      err.write(Constants.encode(message.toString()));
+      err.write(Constants.encode(message));
       err.flush();
 
       in.close();
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SingleCommandPluginModule.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SingleCommandPluginModule.java
new file mode 100644
index 0000000..0c5fca3
--- /dev/null
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SingleCommandPluginModule.java
@@ -0,0 +1,45 @@
+// 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.sshd;
+
+import com.google.common.base.Preconditions;
+import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.inject.binder.LinkedBindingBuilder;
+
+import org.apache.sshd.server.Command;
+
+import javax.inject.Inject;
+
+/**
+ * Binds one SSH command to the plugin name itself.
+ * <p>
+ * Cannot be combined with {@link PluginCommandModule}.
+ */
+public abstract class SingleCommandPluginModule extends CommandModule {
+  private CommandName command;
+
+  @Inject
+  void setPluginName(@PluginName String name) {
+    this.command = Commands.named(name);
+  }
+
+  @Override
+  protected final void configure() {
+    Preconditions.checkState(command != null, "@PluginName must be provided");
+    configure(bind(Commands.key(command)));
+  }
+
+  protected abstract void configure(LinkedBindingBuilder<Command> bind);
+}
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 8519e94..bafc388 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
@@ -15,7 +15,6 @@
 package com.google.gerrit.sshd;
 
 import static com.google.gerrit.server.ssh.SshAddressesModule.IANA_SSH_PORT;
-
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.SECONDS;
 
@@ -35,20 +34,18 @@
 import com.jcraft.jsch.HostKey;
 import com.jcraft.jsch.JSchException;
 
-import org.apache.mina.core.future.IoFuture;
-import org.apache.mina.core.future.IoFutureListener;
-import org.apache.mina.core.service.IoAcceptor;
-import org.apache.mina.core.session.IoSession;
 import org.apache.mina.transport.socket.SocketSessionConfig;
 import org.apache.sshd.SshServer;
 import org.apache.sshd.common.Channel;
 import org.apache.sshd.common.Cipher;
 import org.apache.sshd.common.Compression;
+import org.apache.sshd.common.ForwardingFilter;
 import org.apache.sshd.common.KeyExchange;
 import org.apache.sshd.common.KeyPairProvider;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.Session;
 import org.apache.sshd.common.Signature;
+import org.apache.sshd.common.SshdSocketAddress;
 import org.apache.sshd.common.cipher.AES128CBC;
 import org.apache.sshd.common.cipher.AES192CBC;
 import org.apache.sshd.common.cipher.AES256CBC;
@@ -56,6 +53,19 @@
 import org.apache.sshd.common.cipher.CipherNone;
 import org.apache.sshd.common.cipher.TripleDESCBC;
 import org.apache.sshd.common.compression.CompressionNone;
+import org.apache.sshd.common.file.FileSystemFactory;
+import org.apache.sshd.common.file.FileSystemView;
+import org.apache.sshd.common.file.SshFile;
+import org.apache.sshd.common.forward.DefaultTcpipForwarderFactory;
+import org.apache.sshd.common.forward.TcpipServerChannel;
+import org.apache.sshd.common.future.CloseFuture;
+import org.apache.sshd.common.future.SshFutureListener;
+import org.apache.sshd.common.io.IoAcceptor;
+import org.apache.sshd.common.io.IoServiceFactory;
+import org.apache.sshd.common.io.IoSession;
+import org.apache.sshd.common.io.mina.MinaServiceFactory;
+import org.apache.sshd.common.io.mina.MinaSession;
+import org.apache.sshd.common.io.nio2.Nio2ServiceFactory;
 import org.apache.sshd.common.mac.HMACMD5;
 import org.apache.sshd.common.mac.HMACMD596;
 import org.apache.sshd.common.mac.HMACSHA1;
@@ -63,26 +73,21 @@
 import org.apache.sshd.common.random.BouncyCastleRandom;
 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.signature.SignatureDSA;
 import org.apache.sshd.common.signature.SignatureRSA;
 import org.apache.sshd.common.util.Buffer;
 import org.apache.sshd.common.util.SecurityUtils;
 import org.apache.sshd.server.Command;
 import org.apache.sshd.server.CommandFactory;
-import org.apache.sshd.server.FileSystemFactory;
-import org.apache.sshd.server.FileSystemView;
-import org.apache.sshd.server.ForwardingFilter;
 import org.apache.sshd.server.PublickeyAuthenticator;
-import org.apache.sshd.server.SshFile;
 import org.apache.sshd.server.UserAuth;
 import org.apache.sshd.server.auth.UserAuthPublicKey;
 import org.apache.sshd.server.auth.gss.GSSAuthenticator;
 import org.apache.sshd.server.auth.gss.UserAuthGSS;
-import org.apache.sshd.server.channel.ChannelDirectTcpip;
 import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.kex.DHG1;
 import org.apache.sshd.server.kex.DHG14;
-import org.apache.sshd.server.session.ServerSession;
 import org.apache.sshd.server.session.SessionFactory;
 import org.eclipse.jgit.lib.Config;
 import org.slf4j.Logger;
@@ -91,7 +96,6 @@
 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;
@@ -126,6 +130,11 @@
 public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
   private static final Logger log = LoggerFactory.getLogger(SshDaemon.class);
 
+  public static enum SshSessionBackend {
+    MINA,
+    NIO2
+  }
+
   private final List<SocketAddress> listen;
   private final List<String> advertised;
   private final boolean keepAlive;
@@ -144,7 +153,6 @@
 
     this.listen = listen;
     this.advertised = advertised;
-    reuseAddress = cfg.getBoolean("sshd", "reuseaddress", true);
     keepAlive = cfg.getBoolean("sshd", "tcpkeepalive", true);
 
     getProperties().put(SERVER_IDENTIFICATION,
@@ -161,12 +169,6 @@
 
     long idleTimeoutSeconds = ConfigUtil.getTimeUnit(cfg, "sshd", null,
         "idleTimeout", 0, SECONDS);
-    if (idleTimeoutSeconds == 0) {
-      // Since Apache SSHD does not allow to turn off closing idle connections,
-      // we fake it by using the highest timeout allowed by Apache SSHD, which
-      // amounts to ~24 days.
-      idleTimeoutSeconds = MILLISECONDS.toSeconds(Integer.MAX_VALUE);
-    }
     getProperties().put(
         IDLE_TIMEOUT,
         String.valueOf(SECONDS.toMillis(idleTimeoutSeconds)));
@@ -183,6 +185,14 @@
     final String kerberosPrincipal = cfg.getString(
         "sshd", null, "kerberosPrincipal");
 
+    SshSessionBackend backend = cfg.getEnum(
+        "sshd", null, "backend", SshSessionBackend.MINA);
+
+    System.setProperty(IoServiceFactory.class.getName(),
+        backend == SshSessionBackend.MINA
+            ? MinaServiceFactory.class.getName()
+            : Nio2ServiceFactory.class.getName());
+
     if (SecurityUtils.isBouncyCastleRegistered()) {
       initProviderBouncyCastle();
     } else {
@@ -192,7 +202,7 @@
     initMacs(cfg);
     initSignatures();
     initChannels();
-    initForwardingFilter();
+    initForwarding();
     initFileSystemFactory();
     initSubsystems();
     initCompression();
@@ -202,24 +212,28 @@
     setShellFactory(noShell);
     setSessionFactory(new SessionFactory() {
       @Override
-      protected ServerSession createSession(final IoSession io)
+      protected AbstractSession createSession(final IoSession io)
           throws Exception {
-        if (io.getConfig() instanceof SocketSessionConfig) {
-          final SocketSessionConfig c = (SocketSessionConfig) io.getConfig();
-          c.setKeepAlive(keepAlive);
+        if (io instanceof MinaSession) {
+          if (((MinaSession) io).getSession()
+              .getConfig() instanceof SocketSessionConfig) {
+            ((SocketSessionConfig) ((MinaSession) io).getSession()
+                .getConfig())
+                .setKeepAlive(keepAlive);
+          }
         }
 
-        final ServerSession s = (ServerSession) super.createSession(io);
-        final int id = idGenerator.next();
-        final SocketAddress peer = io.getRemoteAddress();
+        GerritServerSession s = (GerritServerSession)super.createSession(io);
+        int id = idGenerator.next();
+        SocketAddress peer = io.getRemoteAddress();
         final SshSession sd = new SshSession(id, peer);
         s.setAttribute(SshSession.KEY, sd);
 
         // Log a session close without authentication as a failure.
         //
-        io.getCloseFuture().addListener(new IoFutureListener<IoFuture>() {
+        s.addCloseSessionListener(new SshFutureListener<CloseFuture>() {
           @Override
-          public void operationComplete(IoFuture future) {
+          public void operationComplete(CloseFuture future) {
             if (sd.isAuthenticationError()) {
               sshLog.onAuthFail(sd);
             }
@@ -227,6 +241,12 @@
         });
         return s;
       }
+
+      @Override
+      protected AbstractSession doCreateSession(IoSession ioSession)
+          throws Exception {
+        return new GerritServerSession(server, ioSession);
+      }
     });
 
     hostKeys = computeHostKeys();
@@ -245,13 +265,11 @@
   public synchronized void start() {
     if (acceptor == null && !listen.isEmpty()) {
       checkConfig();
-
+      if (sessionFactory == null) {
+        sessionFactory = createSessionFactory();
+      }
+      sessionFactory.setServer(this);
       acceptor = createAcceptor();
-      configure(acceptor);
-
-      final SessionFactory handler = getSessionFactory();
-      handler.setServer(this);
-      acceptor.setHandler(handler);
 
       try {
         acceptor.bind(listen);
@@ -259,7 +277,8 @@
         throw new IllegalStateException("Cannot bind to " + addressList(), e);
       }
 
-      log.info("Started Gerrit SSHD on " + addressList());
+      log.info(String.format("Started Gerrit %s on %s",
+          version, addressList()));
     }
   }
 
@@ -473,7 +492,7 @@
   private void initChannels() {
     setChannelFactories(Arrays.<NamedFactory<Channel>> asList(
         new ChannelSession.Factory(), //
-        new ChannelDirectTcpip.Factory() //
+        new TcpipServerChannel.DirectTcpipFactory() //
         ));
   }
 
@@ -514,28 +533,29 @@
     setPublickeyAuthenticator(pubkey);
   }
 
-  private void initForwardingFilter() {
-    setForwardingFilter(new ForwardingFilter() {
+  private void initForwarding() {
+    setTcpipForwardingFilter(new ForwardingFilter() {
       @Override
-      public boolean canForwardAgent(ServerSession session) {
-        return false;
+      public boolean canForwardAgent(Session session) {
+          return false;
       }
 
       @Override
-      public boolean canForwardX11(ServerSession session) {
-        return false;
+      public boolean canForwardX11(Session session) {
+          return false;
       }
 
       @Override
-      public boolean canConnect(InetSocketAddress address, ServerSession session) {
-        return false;
+      public boolean canListen(SshdSocketAddress address, Session session) {
+          return false;
       }
 
       @Override
-      public boolean canListen(InetSocketAddress address, ServerSession session) {
-        return false;
+      public boolean canConnect(SshdSocketAddress address, Session session) {
+          return false;
       }
     });
+    setTcpipForwarderFactory(new DefaultTcpipForwarderFactory());
   }
 
   private void initFileSystemFactory() {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java
index 39b7f16..2322a3b 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java
@@ -21,7 +21,6 @@
 import com.google.gerrit.lifecycle.LifecycleModule;
 import com.google.gerrit.server.PeerDaemonUser;
 import com.google.gerrit.server.RemotePeer;
-import com.google.gerrit.server.config.FactoryModule;
 import com.google.gerrit.server.config.GerritRequestModule;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.git.AsyncReceiveCommits;
@@ -47,7 +46,7 @@
 import java.util.Map;
 
 /** Configures standard dependencies for {@link SshDaemon}. */
-public class SshModule extends FactoryModule {
+public class SshModule extends LifecycleModule {
   private final Map<String, String> aliases;
 
   @Inject
@@ -87,25 +86,20 @@
 
     install(new DefaultCommandModule());
 
-    install(new LifecycleModule() {
-      @Override
-      protected void configure() {
-        bind(ModuleGenerator.class).to(SshAutoRegisterModuleGenerator.class);
-        bind(SshPluginStarterCallback.class);
-        bind(StartPluginListener.class)
-          .annotatedWith(UniqueAnnotations.create())
-          .to(SshPluginStarterCallback.class);
+    bind(ModuleGenerator.class).to(SshAutoRegisterModuleGenerator.class);
+    bind(SshPluginStarterCallback.class);
+    bind(StartPluginListener.class)
+      .annotatedWith(UniqueAnnotations.create())
+      .to(SshPluginStarterCallback.class);
 
-        bind(ReloadPluginListener.class)
-          .annotatedWith(UniqueAnnotations.create())
-          .to(SshPluginStarterCallback.class);
+    bind(ReloadPluginListener.class)
+      .annotatedWith(UniqueAnnotations.create())
+      .to(SshPluginStarterCallback.class);
 
-        listener().toInstance(registerInParentInjectors());
-        listener().to(SshLog.class);
-        listener().to(SshDaemon.class);
-        listener().to(CommandFactoryProvider.class);
-      }
-    });
+    listener().toInstance(registerInParentInjectors());
+    listener().to(SshLog.class);
+    listener().to(SshDaemon.class);
+    listener().to(CommandFactoryProvider.class);
   }
 
   private void configureAliases() {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshRemotePeerProvider.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshRemotePeerProvider.java
index 29ede85..2c77360 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshRemotePeerProvider.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshRemotePeerProvider.java
@@ -21,7 +21,7 @@
 import java.net.SocketAddress;
 
 @Singleton
-class SshRemotePeerProvider implements Provider<SocketAddress> {
+public class SshRemotePeerProvider implements Provider<SocketAddress> {
   private final Provider<SshSession> session;
 
   @Inject
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 440f236..9067b9b 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
@@ -35,7 +35,7 @@
 import java.util.Map;
 
 /** Guice scopes for state during an SSH connection. */
-class SshScope {
+public class SshScope {
   private static final Key<RequestCleanup> RC_KEY =
       Key.get(RequestCleanup.class);
 
@@ -119,7 +119,7 @@
     }
   }
 
-  static class SshSessionProvider implements Provider<SshSession> {
+  public static class SshSessionProvider implements Provider<SshSession> {
     @Override
     public SshSession get() {
       return requireContext().getSession();
@@ -181,7 +181,7 @@
   }
 
   /** Returns exactly one instance per command executed. */
-  static final Scope REQUEST = new Scope() {
+  public static final Scope REQUEST = new Scope() {
     public <T> Provider<T> scope(final Key<T> key, final Provider<T> creator) {
       return new Provider<T>() {
         public T get() {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshUtil.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshUtil.java
index fc1303c..a2f2c1d 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshUtil.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshUtil.java
@@ -21,8 +21,8 @@
 import com.google.gerrit.sshd.SshScope.Context;
 
 import org.apache.commons.codec.binary.Base64;
-import org.apache.mina.core.future.IoFuture;
-import org.apache.mina.core.future.IoFutureListener;
+import org.apache.sshd.common.future.CloseFuture;
+import org.apache.sshd.common.future.SshFutureListener;
 import org.apache.sshd.common.KeyPairProvider;
 import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.util.Buffer;
@@ -138,10 +138,11 @@
         sshScope.set(old);
       }
 
-      session.getIoSession().getCloseFuture().addListener(
-          new IoFutureListener<IoFuture>() {
+      GerritServerSession s = (GerritServerSession) session;
+      s.addCloseSessionListener(
+          new SshFutureListener<CloseFuture>() {
             @Override
-            public void operationComplete(IoFuture future) {
+            public void operationComplete(CloseFuture future) {
               final Context ctx = sshScope.newContext(null, sd, null);
               final Context old = sshScope.set(ctx);
               try {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/DefaultCommandModule.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/DefaultCommandModule.java
index 429caf6..75743b0 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/DefaultCommandModule.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/DefaultCommandModule.java
@@ -14,7 +14,6 @@
 
 package com.google.gerrit.sshd.commands;
 
-import com.google.gerrit.lifecycle.LifecycleModule;
 import com.google.gerrit.sshd.CommandModule;
 import com.google.gerrit.sshd.CommandName;
 import com.google.gerrit.sshd.Commands;
@@ -77,11 +76,6 @@
 
     command("suexec").to(SuExec.class);
 
-    install(new LifecycleModule() {
-      @Override
-      protected void configure() {
-        listener().to(ShowCaches.StartupListener.class);
-      }
-    });
+    listener().to(ShowCaches.StartupListener.class);
   }
 }
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 5649843..69763d6 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/QueryShell.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/QueryShell.java
@@ -51,7 +51,7 @@
   }
 
   public static enum OutputFormat {
-    PRETTY, JSON, JSON_SINGLE;
+    PRETTY, JSON, JSON_SINGLE
   }
 
   private final BufferedReader in;
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 e5eb567..6665a25 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
@@ -22,23 +22,20 @@
 import com.google.gerrit.common.data.LabelValue;
 import com.google.gerrit.common.data.ReviewResult;
 import com.google.gerrit.common.data.ReviewResult.Error.Type;
+import com.google.gerrit.extensions.api.GerritApi;
+import com.google.gerrit.extensions.api.changes.AbandonInput;
+import com.google.gerrit.extensions.api.changes.RestoreInput;
+import com.google.gerrit.extensions.api.changes.ReviewInput;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.BadRequestException;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
+import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.client.RevId;
 import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gerrit.server.change.Abandon;
-import com.google.gerrit.server.change.ChangeResource;
-import com.google.gerrit.server.change.DeleteDraftPatchSet;
-import com.google.gerrit.server.change.PostReview;
-import com.google.gerrit.server.change.Restore;
-import com.google.gerrit.server.change.RevisionResource;
-import com.google.gerrit.server.change.Submit;
 import com.google.gerrit.server.changedetail.PublishDraft;
 import com.google.gerrit.server.config.AllProjectsName;
-import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.InvalidChangeOperationException;
 import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.project.NoSuchProjectException;
@@ -131,32 +128,17 @@
   private ReviewDb db;
 
   @Inject
-  private DeleteDraftPatchSet deleteDraftPatchSetImpl;
-
-  @Inject
   private ProjectControl.Factory projectControlFactory;
 
   @Inject
   private AllProjectsName allProjects;
 
   @Inject
-  private ChangeControl.Factory changeControlFactory;
-
-  @Inject
-  private Provider<Abandon> abandonProvider;
-
-  @Inject
-  private Provider<PostReview> reviewProvider;
+  private Provider<GerritApi> gApi;
 
   @Inject
   private PublishDraft.Factory publishDraftFactory;
 
-  @Inject
-  private Provider<Restore> restoreProvider;
-
-  @Inject
-  private Provider<Submit> submitProvider;
-
   private List<ApproveOption> optionList;
   private Map<String, Short> customLabels;
 
@@ -212,10 +194,12 @@
     }
   }
 
-  private void applyReview(final ChangeControl ctl, final PatchSet patchSet,
-      final PostReview.Input review) throws Exception {
-    reviewProvider.get().apply(new RevisionResource(
-        new ChangeResource(ctl), patchSet), review);
+  private void applyReview(PatchSet patchSet,
+      final ReviewInput review) throws Exception {
+    gApi.get().changes()
+        .id(patchSet.getId().getParentKey().get())
+        .revision(patchSet.getRevision().get())
+        .review(review);
   }
 
   private void approveOne(final PatchSet patchSet) throws Exception {
@@ -224,10 +208,10 @@
       changeComment = "";
     }
 
-    PostReview.Input review = new PostReview.Input();
+    ReviewInput review = new ReviewInput();
     review.message = Strings.emptyToNull(changeComment);
     review.labels = Maps.newTreeMap();
-    review.drafts = PostReview.DraftHandling.PUBLISH;
+    review.drafts = ReviewInput.DraftHandling.PUBLISH;
     review.strictLabels = false;
     for (ApproveOption ao : optionList) {
       Short v = ao.value();
@@ -245,44 +229,41 @@
     }
 
     try {
-      ChangeControl ctl =
-          changeControlFactory.controlFor(patchSet.getId().getParentKey());
-
       if (abandonChange) {
-        final Abandon abandon = abandonProvider.get();
-        final Abandon.Input input = new Abandon.Input();
+        AbandonInput input = new AbandonInput();
         input.message = changeComment;
-        applyReview(ctl, patchSet, review);
+        applyReview(patchSet, review);
         try {
-          abandon.apply(new ChangeResource(ctl), input);
+          gApi.get().changes()
+              .id(patchSet.getId().getParentKey().get())
+              .abandon(input);
         } catch (AuthException e) {
           writeError("error: " + parseError(Type.ABANDON_NOT_PERMITTED) + "\n");
         } catch (ResourceConflictException e) {
           writeError("error: " + parseError(Type.CHANGE_IS_CLOSED) + "\n");
         }
       } else if (restoreChange) {
-        final Restore restore = restoreProvider.get();
-        final Restore.Input input = new Restore.Input();
+        RestoreInput input = new RestoreInput();
         input.message = changeComment;
         try {
-          restore.apply(new ChangeResource(ctl), input);
-          applyReview(ctl, patchSet, review);
+          gApi.get().changes()
+              .id(patchSet.getId().getParentKey().get())
+              .restore(input);
+          applyReview(patchSet, review);
         } catch (AuthException e) {
           writeError("error: " + parseError(Type.RESTORE_NOT_PERMITTED) + "\n");
         } catch (ResourceConflictException e) {
           writeError("error: " + parseError(Type.CHANGE_NOT_ABANDONED) + "\n");
         }
       } else {
-        applyReview(ctl, patchSet, review);
+        applyReview(patchSet, review);
       }
 
       if (submitChange) {
-        Submit submit = submitProvider.get();
-        Submit.Input input = new Submit.Input();
-        input.waitForMerge = true;
-        submit.apply(new RevisionResource(
-            new ChangeResource(ctl), patchSet),
-          input);
+        gApi.get().changes()
+            .id(patchSet.getId().getParentKey().get())
+            .revision(patchSet.getRevision().get())
+            .submit();
       }
 
       if (publishPatchSet) {
@@ -290,9 +271,10 @@
             publishDraftFactory.create(patchSet.getId()).call();
         handleReviewResultErrors(result);
       } else if (deleteDraftPatchSet) {
-        deleteDraftPatchSetImpl.apply(new RevisionResource(
-            new ChangeResource(ctl), patchSet),
-            new DeleteDraftPatchSet.Input());
+        gApi.get().changes()
+            .id(patchSet.getId().getParentKey().get())
+            .revision(patchSet.getRevision().get())
+            .delete();
       }
     } catch (InvalidChangeOperationException e) {
       throw error(e.getMessage());
@@ -304,6 +286,8 @@
       throw error(e.getMessage());
     } catch (ResourceConflictException e) {
       throw error(e.getMessage());
+    } catch (RestApiException e) {
+      throw error(e.getMessage());
     }
   }
 
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 6dc79ff..7fc3a40 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
@@ -118,7 +118,7 @@
     DeleteReviewer delete = deleteReviewerProvider.get();
     for (Account.Id reviewer : toRemove) {
       ReviewerResource rsrc = reviewerFactory.create(changeRsrc, reviewer);
-      String error = null;;
+      String error = null;
       try {
         delete.apply(rsrc, new DeleteReviewer.Input());
       } catch (ResourceNotFoundException e) {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowCaches.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowCaches.java
index 89ba6ba..ff1de80 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowCaches.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowCaches.java
@@ -32,8 +32,9 @@
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
-import org.apache.mina.core.service.IoAcceptor;
-import org.apache.mina.core.session.IoSession;
+import org.apache.sshd.common.io.IoAcceptor;
+import org.apache.sshd.common.io.IoSession;
+import org.apache.sshd.common.io.mina.MinaSession;
 import org.apache.sshd.server.Environment;
 import org.eclipse.jgit.internal.storage.file.WindowCacheStatAccessor;
 import org.kohsuke.args4j.Option;
@@ -274,8 +275,12 @@
     long now = TimeUtil.nowMs();
     Collection<IoSession> list = acceptor.getManagedSessions().values();
     long oldest = now;
+
     for (IoSession s : list) {
-      oldest = Math.min(oldest, s.getCreationTime());
+      if (s instanceof MinaSession) {
+        MinaSession minaSession = (MinaSession)s;
+        oldest = Math.min(oldest, minaSession.getSession().getCreationTime());
+      }
     }
 
     stdout.format(
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 f8531ed..d97d750 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
@@ -26,8 +26,9 @@
 import com.google.gerrit.sshd.SshSession;
 import com.google.inject.Inject;
 
-import org.apache.mina.core.service.IoAcceptor;
-import org.apache.mina.core.session.IoSession;
+import org.apache.sshd.common.io.IoAcceptor;
+import org.apache.sshd.common.io.IoSession;
+import org.apache.sshd.common.io.mina.MinaSession;
 import org.apache.sshd.server.Environment;
 import org.apache.sshd.server.session.ServerSession;
 import org.kohsuke.args4j.Option;
@@ -84,10 +85,16 @@
     Collections.sort(list, new Comparator<IoSession>() {
       @Override
       public int compare(IoSession arg0, IoSession arg1) {
-        if (arg0.getCreationTime() < arg1.getCreationTime()) {
-          return -1;
-        } else if (arg0.getCreationTime() > arg1.getCreationTime()) {
-          return 1;
+        if (arg0 instanceof MinaSession) {
+          MinaSession mArg0 = (MinaSession) arg0;
+          MinaSession mArg1 = (MinaSession) arg1;
+          if (mArg0.getSession().getCreationTime() < mArg1.getSession()
+              .getCreationTime()) {
+            return -1;
+          } else if (mArg0.getSession().getCreationTime() > mArg1.getSession()
+              .getCreationTime()) {
+            return 1;
+          }
         }
         return (int) (arg0.getId() - arg1.getId());
       }
@@ -104,8 +111,15 @@
       SshSession sd = s != null ? s.getAttribute(SshSession.KEY) : null;
 
       final SocketAddress remoteAddress = io.getRemoteAddress();
-      final long start = io.getCreationTime();
-      final long idle = now - io.getLastIoTime();
+      MinaSession minaSession = io instanceof MinaSession
+          ? (MinaSession) io
+          : null;
+      final long start = minaSession == null
+          ? 0
+          : minaSession.getSession().getCreationTime();
+      final long idle = minaSession == null
+          ? now
+          : now - minaSession.getSession().getLastIoTime();
 
       stdout.print(String.format("%8s %8s %8s   %-15.15s %s\n", //
           id(sd), //
diff --git a/gerrit-war/src/main/java/com/google/gerrit/httpd/SiteInitializer.java b/gerrit-war/src/main/java/com/google/gerrit/httpd/SiteInitializer.java
index 0948c46..0a9386d 100644
--- a/gerrit-war/src/main/java/com/google/gerrit/httpd/SiteInitializer.java
+++ b/gerrit-war/src/main/java/com/google/gerrit/httpd/SiteInitializer.java
@@ -23,13 +23,14 @@
 import java.sql.Connection;
 import java.sql.ResultSet;
 import java.sql.SQLException;
+import java.sql.Statement;
 
 public final class SiteInitializer {
-  private static final Logger log = LoggerFactory
+  private static final Logger LOG = LoggerFactory
       .getLogger(SiteInitializer.class);
 
-  final String sitePath;
-  final String initPath;
+  private final String sitePath;
+  private final String initPath;
 
   SiteInitializer(String sitePath, String initPath) {
     this.sitePath = sitePath;
@@ -38,10 +39,9 @@
 
   public void init() {
     try {
-
       if (sitePath != null) {
         File site = new File(sitePath);
-        log.info(String.format("Initializing site at %s",
+        LOG.info(String.format("Initializing site at %s",
             site.getAbsolutePath()));
         new BaseInit(site, false).run();
         return;
@@ -53,9 +53,8 @@
         if (site == null && initPath != null) {
           site = new File(initPath);
         }
-
         if (site != null) {
-          log.info(String.format("Initializing site at %s",
+          LOG.info(String.format("Initializing site at %s",
               site.getAbsolutePath()));
           new BaseInit(site, new ReviewDbDataSourceProvider(), false).run();
         }
@@ -63,7 +62,7 @@
         conn.close();
       }
     } catch (Exception e) {
-      log.error("Site init failed", e);
+      LOG.error("Site init failed", e);
       throw new RuntimeException(e);
     }
   }
@@ -74,10 +73,14 @@
 
   private File getSiteFromReviewDb(Connection conn) {
     try {
-      ResultSet rs = conn.createStatement().executeQuery(
-          "select site_path from system_config");
-      if (rs.next()) {
-        return new File(rs.getString(1));
+      Statement stmt = conn.createStatement();
+      try {
+        ResultSet rs = stmt.executeQuery("SELECT site_path FROM system_config");
+        if (rs.next()) {
+          return new File(rs.getString(1));
+        }
+      } finally {
+        stmt.close();
       }
       return null;
     } catch (SQLException e) {
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 5936911..36595c0 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
@@ -196,16 +196,10 @@
       final DataSourceType dst = Guice.createInjector(new DataSourceModule(),
           configModule, sitePathModule).getInstance(
             Key.get(DataSourceType.class, Names.named(dbType.toLowerCase())));
-      modules.add(new AbstractModule() {
-        @Override
-        protected void configure() {
-          bind(DataSourceType.class).toInstance(dst);
-        }
-      });
-
       modules.add(new LifecycleModule() {
         @Override
         protected void configure() {
+          bind(DataSourceType.class).toInstance(dst);
           bind(DataSourceProvider.Context.class).toInstance(
               DataSourceProvider.Context.MULTI_USER);
           bind(Key.get(DataSource.class, Names.named("ReviewDb"))).toProvider(
diff --git a/gerrit-war/src/main/resources/log4j.properties b/gerrit-war/src/main/resources/log4j.properties
index 1fcca6d..cb14916 100644
--- a/gerrit-war/src/main/resources/log4j.properties
+++ b/gerrit-war/src/main/resources/log4j.properties
@@ -26,7 +26,7 @@
 log4j.logger.org.apache.sshd.common=WARN
 log4j.logger.org.apache.sshd.server=WARN
 log4j.logger.org.apache.sshd.common.keyprovider.FileKeyPairProvider=INFO
-log4j.logger.com.google.gerrit.server.ssh.GerritServerSession=WARN
+log4j.logger.com.google.gerrit.sshd.GerritServerSession=WARN
 
 # Silence non-critical messages from Jetty.
 #
diff --git a/lib/BUCK b/lib/BUCK
index ade5e95..5ee1bab 100644
--- a/lib/BUCK
+++ b/lib/BUCK
@@ -106,8 +106,8 @@
 
 maven_jar(
   name = 'jsch',
-  id = 'com.jcraft:jsch:0.1.44-1',
-  sha1 = '2e9ae08de5a71bd0e0d3ba2558598181bfa71d4e',
+  id = 'com.jcraft:jsch:0.1.50',
+  sha1 = 'fae4a0b1f2a96cb8f58f38da2650814c991cea01',
   license = 'jsch',
 )
 
@@ -223,8 +223,8 @@
 
 maven_jar(
   name = 'easymock',
-  id = 'org.easymock:easymock:3.1',
-  sha1 = '3e127311a86fc2e8f550ef8ee4abe094bbcf7e7e',
+  id = 'org.easymock:easymock:3.2',
+  sha1 = '00c82f7fa3ef377d8954b1db25123944b5af2ba4',
   license = 'DO_NOT_DISTRIBUTE',
   deps = [
     ':cglib-2_2',
diff --git a/lib/gwt/compiler.py b/lib/gwt/compiler.py
index 32fd91c..f7b478c 100755
--- a/lib/gwt/compiler.py
+++ b/lib/gwt/compiler.py
@@ -54,8 +54,12 @@
   '-localWorkers', str(cpu_count()),
 ] + opt + [module]
 
-gwt = Popen(cmd, stdout = PIPE, stderr = PIPE)
-out, err = gwt.communicate()
-if gwt.returncode != 0:
-  print(out + err, file=stderr)
-  exit(gwt.returncode)
+try:
+  gwt = Popen(cmd, stdout=PIPE, stderr=PIPE)
+  out, err = gwt.communicate()
+  if gwt.returncode != 0:
+    print(out + err, file=stderr)
+    exit(gwt.returncode)
+except KeyboardInterrupt:
+  print("Interrupted by user", file=stderr)
+  exit(1)
diff --git a/lib/jgit/BUCK b/lib/jgit/BUCK
index 3e481bf..bc3044f 100644
--- a/lib/jgit/BUCK
+++ b/lib/jgit/BUCK
@@ -26,6 +26,7 @@
   license = 'jgit',
   repository = REPO,
   deps = [':jgit'],
+  unsign = True,
   exclude = [
     'about.html',
     'plugin.properties',
@@ -38,6 +39,7 @@
   sha1 = 'a8b47bb41cec25b1d128f7d267badbc7dcf6d9aa',
   license = 'DO_NOT_DISTRIBUTE',
   repository = REPO,
+  unsign = True,
   deps = [':jgit'],
 )
 
diff --git a/lib/mina/BUCK b/lib/mina/BUCK
index 3e9558a..9467cc4 100644
--- a/lib/mina/BUCK
+++ b/lib/mina/BUCK
@@ -8,17 +8,18 @@
 
 maven_jar(
   name = 'core',
-  id = 'org.apache.mina:mina-core:2.0.5',
-  sha1 = '0e134a3761833a3c28c79331e806f64f985a9eec',
+  id = 'org.apache.mina:mina-core:2.0.7',
+  sha1 = 'c878e2aa82de748474a624ec3933e4604e446dec',
   license = 'Apache2.0',
   exclude = EXCLUDE,
 )
 
 maven_jar(
   name = 'sshd',
-  id = 'org.apache.sshd:sshd-core:0.6.0',
-  sha1 = '2b9a119dd77a1decec78b0c511ba400c8655e96e',
+  id = 'org.apache.sshd:sshd-core:0.9.0.201311081',
+  sha1 = '38f7ac8602e70fa05fdc6147d204198e9cefe5bc',
   license = 'Apache2.0',
   deps = [':core'],
   exclude = EXCLUDE,
+  repository = GERRIT,
 )
diff --git a/plugins/download-commands b/plugins/download-commands
index 32254d3..fe2bc6b 160000
--- a/plugins/download-commands
+++ b/plugins/download-commands
@@ -1 +1 @@
-Subproject commit 32254d3b75d65aceb485950fbf30d464574e02fc
+Subproject commit fe2bc6be5ef964a5df247a85f82c0155dc2f8876
diff --git a/plugins/replication b/plugins/replication
index 6cb2938..c126e78 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit 6cb293834907a7c059aa05168646ebc9f6b68c5a
+Subproject commit c126e78886cd985edddee66ad1aba0130a4a5819
diff --git a/plugins/singleusergroup b/plugins/singleusergroup
new file mode 160000
index 0000000..c9ad9d1
--- /dev/null
+++ b/plugins/singleusergroup
@@ -0,0 +1 @@
+Subproject commit c9ad9d1be42d5139fc1c447df644866f1d23ed15
diff --git a/tools/eclipse/BUCK b/tools/eclipse/BUCK
index 264e4eb..6f4e704 100644
--- a/tools/eclipse/BUCK
+++ b/tools/eclipse/BUCK
@@ -9,6 +9,8 @@
     '//gerrit-gwtui:ui_tests',
     '//gerrit-httpd:httpd_tests',
     '//gerrit-main:main_lib',
+    '//gerrit-patch-jgit:jgit_patch_tests',
+    '//gerrit-plugin-gwtui:client',
     '//gerrit-server:server__compile',
     '//lib/asciidoctor:asciidoc_lib',
     '//lib/asciidoctor:doc_indexer_lib',
diff --git a/tools/maven/BUCK b/tools/maven/BUCK
index 0a470a4..50b403b 100644
--- a/tools/maven/BUCK
+++ b/tools/maven/BUCK
@@ -10,10 +10,12 @@
   jar = {
     'gerrit-extension-api': '//:extension-api',
     'gerrit-plugin-api': '//:plugin-api',
+    'gerrit-plugin-gwtui': '//:plugin-gwtui',
   },
   src = {
     'gerrit-extension-api': '//:extension-api-src',
     'gerrit-plugin-api': '//:plugin-api-src',
+    'gerrit-plugin-gwtui': '//:plugin-gwtui-src',
   },
 )