Merge changes Ia2549551,Ia82f8347,Ideee6730

* changes:
  Use CSS constant for assignee color
  Use CSS constants in gr-form-styles
  Replace more CSS vars with constants
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 9a37f25..ce7adc2 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -1140,7 +1140,8 @@
 
 [[change.allowBlame]]change.allowBlame::
 +
-Allow blame on side by side diff. If set to false, blame cannot be used.
+Allow blame on side by side diff in the GWT UI. If set to false, blame cannot be
+used.
 +
 Default is true.
 
@@ -2974,13 +2975,13 @@
 version 2.4.x. Support for other versions is not guaranteed.
 
 Open and closed changes are indexed in a single index, separated
-into types 'open_changes' and 'closed_changes' respectively.
+into types `open_changes` and `closed_changes` respectively.
 
 [[elasticsearch.prefix]]elasticsearch.prefix::
 +
 This setting can be used to prefix index names to allow multiple Gerrit
-instances in a single Elasticsearch cluster. Prefix 'gerrit1_' would result in a
-change index named 'gerrit1_changes_0001'.
+instances in a single Elasticsearch cluster. Prefix `gerrit1_` would result in a
+change index named `gerrit1_changes_0001`.
 +
 Not set by default.
 
@@ -3006,7 +3007,7 @@
 +
 How long should Gerrit waits for connection.
 +
-The value is in the usual time-unit format like "1 m", "5 m".
+The value is in the usual time-unit format like `1 m`, `5 m`.
 +
 Defaults to `5 m`
 
@@ -3014,31 +3015,31 @@
 +
 How long connection can stay in idle.
 +
-The value is in the usual time-unit format like "1 m", "5 m".
+The value is in the usual time-unit format like `1 m`, `5 m`.
 +
 Defaults to `5 m`
 
 [[elasticsearch.maxTotalConnection]]elasticsearch.maxTotalConnection::
 +
-How many connections can be spawn simultaneously.
+How many connections can be spawned simultaneously.
 +
 Defaults to `1`
 
 [[elasticsearch.maxReadTimeout]]elasticsearch.maxReadTimeout::
 +
-Timeout for the read operation.
+Timeout for read operations.
 +
-The value is in the usual time-unit format like "1 m", "5 m".
+The value is in the usual time-unit format like `1 m`, `5 m`.
 +
 Defaults to `5 m`
 
 ==== Elasticsearch server(s) configuration
 
-Each section correspond to one Elasticsearch server.
+Each section corresponds to one Elasticsearch server.
 
 [[elasticsearch.name.protocol]]elasticsearch.name.protocol::
 +
-Elasticsearch server protocol [http|https].
+Elasticsearch server protocol. Can be `http` or `https`.
 +
 Defaults to `http`.
 
diff --git a/Documentation/metrics.txt b/Documentation/metrics.txt
index 742c8c2..640178e 100644
--- a/Documentation/metrics.txt
+++ b/Documentation/metrics.txt
@@ -68,6 +68,17 @@
 * `query/query_latency`: Successful query latency, accumulated over the life
 of the process.
 
+=== Queue
+
+The metrics below are per queue.
+
+* `queue/<queueName>/pool_size`: Current number of threads in the pool
+* `queue/<queueName>/max_pool_size`: Maximum allowed number of threads in the pool
+* `queue/<queueName>/active_threads`: Number of threads that are actively executing tasks
+* `queue/<queueName>/scheduled_tasks`: Number of scheduled tasks in the queue
+* `queue/<queueName>/total_scheduled_tasks_count`: Total number of tasks that have been scheduled
+* `queue/<queueName>/total_completed_tasks_count`: Total number of tasks that have completed execution
+
 === SSH sessions
 
 * `sshd/sessions/connected`: Number of currently connected SSH sessions.
diff --git a/contrib/populate-fixture-data.py b/contrib/populate-fixture-data.py
index 99d9a49..93ac34f 100755
--- a/contrib/populate-fixture-data.py
+++ b/contrib/populate-fixture-data.py
@@ -21,6 +21,7 @@
 TODO(hiesel): Add comments
 """
 
+from __future__ import print_function
 import atexit
 import json
 import optparse
@@ -280,7 +281,7 @@
   (options, _) = p.parse_args()
   global BASE_URL
   BASE_URL = BASE_URL % options.port
-  print BASE_URL
+  print(BASE_URL)
 
   set_up()
   gerrit_users = get_random_users(options.user_count)
diff --git a/java/com/google/gerrit/httpd/gitweb/GitwebServlet.java b/java/com/google/gerrit/httpd/gitweb/GitwebServlet.java
index 19172e2..5b60a36f 100644
--- a/java/com/google/gerrit/httpd/gitweb/GitwebServlet.java
+++ b/java/com/google/gerrit/httpd/gitweb/GitwebServlet.java
@@ -423,10 +423,7 @@
       }
 
       projectState.checkStatePermitsRead();
-      permissionBackend
-          .user(anonymousUserProvider.get())
-          .project(nameKey)
-          .check(ProjectPermission.READ);
+      permissionBackend.user(userProvider.get()).project(nameKey).check(ProjectPermission.READ);
     } catch (AuthException e) {
       sendErrorOrRedirect(req, rsp, HttpServletResponse.SC_NOT_FOUND);
       return;
diff --git a/java/com/google/gerrit/server/api/GerritApiImpl.java b/java/com/google/gerrit/server/api/GerritApiImpl.java
index 6a6415e..24fad34 100644
--- a/java/com/google/gerrit/server/api/GerritApiImpl.java
+++ b/java/com/google/gerrit/server/api/GerritApiImpl.java
@@ -25,7 +25,7 @@
 import com.google.inject.Singleton;
 
 @Singleton
-class GerritApiImpl implements GerritApi {
+public class GerritApiImpl implements GerritApi {
   private final Accounts accounts;
   private final Changes changes;
   private final Config config;
diff --git a/java/com/google/gerrit/server/git/WorkQueue.java b/java/com/google/gerrit/server/git/WorkQueue.java
index 74f986e..29915ef5 100644
--- a/java/com/google/gerrit/server/git/WorkQueue.java
+++ b/java/com/google/gerrit/server/git/WorkQueue.java
@@ -14,8 +14,12 @@
 
 package com.google.gerrit.server.git;
 
+import com.google.common.base.CaseFormat;
+import com.google.common.base.Supplier;
 import com.google.gerrit.extensions.events.LifecycleListener;
 import com.google.gerrit.lifecycle.LifecycleModule;
+import com.google.gerrit.metrics.Description;
+import com.google.gerrit.metrics.MetricMaker;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.ScheduleConfig.Schedule;
@@ -84,17 +88,19 @@
         }
       };
 
+  private final MetricMaker metrics;
   private final ScheduledExecutorService defaultQueue;
   private final IdGenerator idGenerator;
   private final CopyOnWriteArrayList<Executor> queues;
 
   @Inject
-  WorkQueue(IdGenerator idGenerator, @GerritServerConfig Config cfg) {
-    this(idGenerator, cfg.getInt("execution", "defaultThreadPoolSize", 1));
+  WorkQueue(MetricMaker metrics, IdGenerator idGenerator, @GerritServerConfig Config cfg) {
+    this(metrics, idGenerator, cfg.getInt("execution", "defaultThreadPoolSize", 1));
   }
 
   /** Constructor to allow binding the WorkQueue more explicitly in a vhost setup. */
-  public WorkQueue(IdGenerator idGenerator, int defaultThreadPoolSize) {
+  public WorkQueue(MetricMaker metrics, IdGenerator idGenerator, int defaultThreadPoolSize) {
+    this.metrics = metrics;
     this.idGenerator = idGenerator;
     this.queues = new CopyOnWriteArrayList<>();
     this.defaultQueue = createQueue(defaultThreadPoolSize, "WorkQueue");
@@ -224,6 +230,86 @@
               corePoolSize + 4 // concurrency level
               );
       queueName = prefix;
+      buildMetrics(queueName, metrics);
+    }
+
+    private void buildMetrics(String queueName, MetricMaker metric) {
+      metric.newCallbackMetric(
+          getMetricName(queueName, "max_pool_size"),
+          Long.class,
+          new Description("Maximum allowed number of threads in the pool")
+              .setGauge()
+              .setUnit("threads"),
+          new Supplier<Long>() {
+            @Override
+            public Long get() {
+              return (long) getMaximumPoolSize();
+            }
+          });
+      metric.newCallbackMetric(
+          getMetricName(queueName, "pool_size"),
+          Long.class,
+          new Description("Current number of threads in the pool").setGauge().setUnit("threads"),
+          new Supplier<Long>() {
+            @Override
+            public Long get() {
+              return (long) getPoolSize();
+            }
+          });
+      metric.newCallbackMetric(
+          getMetricName(queueName, "active_threads"),
+          Long.class,
+          new Description("Number number of threads that are actively executing tasks")
+              .setGauge()
+              .setUnit("threads"),
+          new Supplier<Long>() {
+            @Override
+            public Long get() {
+              return (long) getActiveCount();
+            }
+          });
+      metric.newCallbackMetric(
+          getMetricName(queueName, "scheduled_tasks"),
+          Integer.class,
+          new Description("Number of scheduled tasks in the queue").setGauge().setUnit("tasks"),
+          new Supplier<Integer>() {
+            @Override
+            public Integer get() {
+              return getQueue().size();
+            }
+          });
+      metric.newCallbackMetric(
+          getMetricName(queueName, "total_scheduled_tasks_count"),
+          Long.class,
+          new Description("Total number of tasks that have been scheduled for execution")
+              .setCumulative()
+              .setUnit("tasks"),
+          new Supplier<Long>() {
+            @Override
+            public Long get() {
+              return (long) getTaskCount();
+            }
+          });
+      metric.newCallbackMetric(
+          getMetricName(queueName, "total_completed_tasks_count"),
+          Long.class,
+          new Description("Total number of tasks that have completed execution")
+              .setCumulative()
+              .setUnit("tasks"),
+          new Supplier<Long>() {
+            @Override
+            public Long get() {
+              return (long) getCompletedTaskCount();
+            }
+          });
+    }
+
+    private String getMetricName(String queueName, String metricName) {
+      String name =
+          CaseFormat.UPPER_CAMEL.to(
+              CaseFormat.LOWER_UNDERSCORE,
+              queueName.replaceFirst("SSH", "Ssh").replaceAll("-", ""));
+      return String.format("queue/%s/%s", name, metricName);
     }
 
     @Override
diff --git a/java/com/google/gerrit/server/restapi/change/GetBlame.java b/java/com/google/gerrit/server/restapi/change/GetBlame.java
index 6bba936..f5c8849 100644
--- a/java/com/google/gerrit/server/restapi/change/GetBlame.java
+++ b/java/com/google/gerrit/server/restapi/change/GetBlame.java
@@ -18,7 +18,6 @@
 import com.google.common.collect.MultimapBuilder;
 import com.google.gerrit.extensions.common.BlameInfo;
 import com.google.gerrit.extensions.common.RangeInfo;
-import com.google.gerrit.extensions.restapi.BadRequestException;
 import com.google.gerrit.extensions.restapi.CacheControl;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
 import com.google.gerrit.extensions.restapi.Response;
@@ -55,7 +54,6 @@
 
   private final GitRepositoryManager repoManager;
   private final BlameCache blameCache;
-  private final boolean allowBlame;
   private final ThreeWayMergeStrategy mergeStrategy;
   private final AutoMerger autoMerger;
 
@@ -78,16 +76,11 @@
     this.blameCache = blameCache;
     this.mergeStrategy = MergeUtil.getMergeStrategy(cfg);
     this.autoMerger = autoMerger;
-    allowBlame = cfg.getBoolean("change", "allowBlame", true);
   }
 
   @Override
   public Response<List<BlameInfo>> apply(FileResource resource)
       throws RestApiException, OrmException, IOException, InvalidChangeOperationException {
-    if (!allowBlame) {
-      throw new BadRequestException("blame is disabled");
-    }
-
     Project.NameKey project = resource.getRevision().getChange().getProject();
     try (Repository repository = repoManager.openRepository(project);
         ObjectInserter ins = repository.newObjectInserter();
diff --git a/java/com/google/gerrit/sshd/SshDaemon.java b/java/com/google/gerrit/sshd/SshDaemon.java
index e61919a..ecd9476 100644
--- a/java/com/google/gerrit/sshd/SshDaemon.java
+++ b/java/com/google/gerrit/sshd/SshDaemon.java
@@ -670,7 +670,7 @@
     List<NamedFactory<UserAuth>> authFactories = new ArrayList<>();
     if (kerberosKeytab != null) {
       authFactories.add(UserAuthGSSFactory.INSTANCE);
-      log.info("Enabling kerberos with keytab " + kerberosKeytab);
+      sshDaemonLog.info("Enabling kerberos with keytab " + kerberosKeytab);
       if (!new File(kerberosKeytab).canRead()) {
         sshDaemonLog.error(
             "Keytab "
diff --git a/javatests/com/google/gerrit/acceptance/api/accounts/AgreementsIT.java b/javatests/com/google/gerrit/acceptance/api/accounts/AgreementsIT.java
index a98d103..c3a0dc9 100644
--- a/javatests/com/google/gerrit/acceptance/api/accounts/AgreementsIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/accounts/AgreementsIT.java
@@ -128,6 +128,23 @@
   }
 
   @Test
+  public void signAgreementAsOtherUser() throws Exception {
+    assume().that(isContributorAgreementsEnabled()).isTrue();
+    assertThat(gApi.accounts().self().get().name).isNotEqualTo("admin");
+    exception.expect(AuthException.class);
+    exception.expectMessage("not allowed to enter contributor agreement");
+    gApi.accounts().id("admin").signAgreement(caAutoVerify.getName());
+  }
+
+  @Test
+  public void signAgreementAnonymous() throws Exception {
+    setApiUserAnonymous();
+    exception.expect(AuthException.class);
+    exception.expectMessage("Authentication required");
+    gApi.accounts().self().signAgreement(caAutoVerify.getName());
+  }
+
+  @Test
   public void agreementsDisabledSign() throws Exception {
     assume().that(isContributorAgreementsEnabled()).isFalse();
     exception.expect(MethodNotAllowedException.class);
diff --git a/javatests/com/google/gerrit/server/cache/BUILD b/javatests/com/google/gerrit/server/cache/BUILD
index 6eca172..eed4a87 100644
--- a/javatests/com/google/gerrit/server/cache/BUILD
+++ b/javatests/com/google/gerrit/server/cache/BUILD
@@ -2,11 +2,13 @@
 
 junit_tests(
     name = "tests",
-    srcs = ["PerThreadCacheTest.java"],
+    srcs = glob(["*.java"]),
     deps = [
         "//java/com/google/gerrit/server",
         "//lib:guava",
         "//lib:junit",
         "//lib:truth",
+        "//lib/auto:auto-value",
+        "//lib/auto:auto-value-annotations",
     ],
 )
diff --git a/plugins/codemirror-editor b/plugins/codemirror-editor
index fa9df30..c97e280 160000
--- a/plugins/codemirror-editor
+++ b/plugins/codemirror-editor
@@ -1 +1 @@
-Subproject commit fa9df3035c306069758712bfe9ae3425b119bb0c
+Subproject commit c97e2806532cff00fea6424cde0d440f9ea5016d
diff --git a/plugins/hooks b/plugins/hooks
index aa42524..da73b23 160000
--- a/plugins/hooks
+++ b/plugins/hooks
@@ -1 +1 @@
-Subproject commit aa4252417f54e28db3a7fa1f98d9a06d8ce49465
+Subproject commit da73b23cfb065fc28c9e7653860ccd34bd68f0f0
diff --git a/polygerrit-ui/app/behaviors/gr-anonymous-name-behavior/gr-anonymous-name-behavior.html b/polygerrit-ui/app/behaviors/gr-anonymous-name-behavior/gr-anonymous-name-behavior.html
index e803e54..40379e4 100644
--- a/polygerrit-ui/app/behaviors/gr-anonymous-name-behavior/gr-anonymous-name-behavior.html
+++ b/polygerrit-ui/app/behaviors/gr-anonymous-name-behavior/gr-anonymous-name-behavior.html
@@ -32,6 +32,8 @@
     getUserName(config, account, enableEmail) {
       if (account && account.name) {
         return account.name;
+      } else if (account && account.username) {
+        return account.username;
       } else if (enableEmail && account && account.email) {
         return account.email;
       } else if (config && config.user &&
diff --git a/polygerrit-ui/app/behaviors/gr-anonymous-name-behavior/gr-anonymous-name-behavior_test.html b/polygerrit-ui/app/behaviors/gr-anonymous-name-behavior/gr-anonymous-name-behavior_test.html
index 9f5c445..3ac94fe 100644
--- a/polygerrit-ui/app/behaviors/gr-anonymous-name-behavior/gr-anonymous-name-behavior_test.html
+++ b/polygerrit-ui/app/behaviors/gr-anonymous-name-behavior/gr-anonymous-name-behavior_test.html
@@ -56,7 +56,14 @@
 
     test('test for it to return name', () => {
       const account = {
-        name: 'test-user',
+        name: 'test-name',
+      };
+      assert.deepEqual(element.getUserName(config, account, true), 'test-name');
+    });
+
+    test('test for it to return username', () => {
+      const account = {
+        username: 'test-user',
       };
       assert.deepEqual(element.getUserName(config, account, true), 'test-user');
     });
diff --git a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.html b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.html
index 48f4ecc..eb6a708 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.html
+++ b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.html
@@ -19,6 +19,7 @@
 <link rel="import" href="../../../bower_components/polymer/polymer.html">
 <link rel="import" href="../../../styles/gr-table-styles.html">
 <link rel="import" href="../../../styles/shared-styles.html">
+<link rel="import" href="../../core/gr-navigation/gr-navigation.html">
 <link rel="import" href="../../shared/gr-date-formatter/gr-date-formatter.html">
 <link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
 
@@ -47,11 +48,20 @@
           </td>
           <td class="type">[[itemType(item.type)]]</td>
           <td class="member">
-            <a href$="[[_computeGroupUrl(item.member.group_id)]]">
-              [[_getNameForMember(item.member)]]
-            </a>
+            <template is="dom-if" if="[[_isGroupEvent(item.type)]]">
+              <a href$="[[_computeGroupUrl(item.member)]]">
+                [[_getNameForGroup(item.member)]]
+              </a>
+            </template>
+            <template is="dom-if" if="[[!_isGroupEvent(item.type)]]">
+              <gr-account-link account="[[item.member]]"></gr-account-link>
+              [[_getIdForUser(item.member)]]
+            </template>
           </td>
-          <td class="by-user">[[_getNameForUser(item.user)]]</td>
+          <td class="by-user">
+            <gr-account-link account="[[item.user]]"></gr-account-link>
+            [[_getIdForUser(item.user)]]
+          </td>
         </tr>
       </template>
     </table>
diff --git a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.js b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.js
index b150d68..bc6a5d0 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.js
+++ b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.js
@@ -17,12 +17,14 @@
 (function() {
   'use strict';
 
+  const GROUP_EVENTS = ['ADD_GROUP', 'REMOVE_GROUP'];
+
   Polymer({
     is: 'gr-group-audit-log',
 
     properties: {
-      groupId: Object,
-      _auditLog: Object,
+      groupId: String,
+      _auditLog: Array,
       _loading: {
         type: Boolean,
         value: true,
@@ -63,12 +65,6 @@
       return item.disabled ? 'Disabled' : 'Enabled';
     },
 
-    _computeGroupUrl(id) {
-      if (!id) { return ''; }
-
-      return this.getBaseUrl() + '/admin/groups/' + id;
-    },
-
     itemType(type) {
       let item;
       switch (type) {
@@ -86,20 +82,31 @@
       return item;
     },
 
-    _getNameForUser(account) {
-      const accountId = account._account_id ? ' (' +
-        account._account_id + ')' : '';
-      return this._getNameForMember(account) + accountId;
+    _isGroupEvent(type) {
+      return GROUP_EVENTS.indexOf(type) !== -1;
     },
 
-    _getNameForMember(account) {
-      if (account && account.name) {
-        return account.name;
-      } else if (account && account.username) {
-        return account.username;
-      } else if (account && account.email) {
-        return account.email.split('@')[0];
+    _computeGroupUrl(group) {
+      if (group && group.url && group.id) {
+        return Gerrit.Nav.getUrlForGroup(group.id);
       }
+
+      return '';
+    },
+
+    _getIdForUser(account) {
+      return account._account_id ? ' (' + account._account_id + ')' : '';
+    },
+
+    _getNameForGroup(group) {
+      if (group && group.name) {
+        return group.name;
+      } else if (group && group.id) {
+        // The URL encoded id of the member
+        return decodeURIComponent(group.id);
+      }
+
+      return '';
     },
   });
 })();
diff --git a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_test.html b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_test.html
index 86e8a25..59a665b 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_test.html
@@ -47,81 +47,49 @@
     });
 
     suite('members', () => {
-      test('test getNameForMember', () => {
-        let account = {
-          member: {
-            username: 'test-user',
-            _account_id: 12,
-          },
-        };
-        assert.equal(element._getNameForMember(account.member, false),
-            'test-user');
-
-        account = {
+      test('test _getNameForGroup', () => {
+        let group = {
           member: {
             name: 'test-name',
-            _account_id: 12,
           },
         };
-        assert.equal(element._getNameForMember(account.member), 'test-name');
+        assert.equal(element._getNameForGroup(group.member), 'test-name');
 
-        account = {
-          user: {
-            email: 'test-email@gmail.com',
+        group = {
+          member: {
+            id: 'test-id',
           },
         };
-        assert.equal(element._getNameForMember(account.user), 'test-email');
+        assert.equal(element._getNameForGroup(group.member), 'test-id');
+      });
+
+      test('test _isGroupEvent', () => {
+        assert.isTrue(element._isGroupEvent('ADD_GROUP'));
+        assert.isTrue(element._isGroupEvent('REMOVE_GROUP'));
+
+        assert.isFalse(element._isGroupEvent('ADD_USER'));
+        assert.isFalse(element._isGroupEvent('REMOVE_USER'));
       });
     });
 
     suite('users', () => {
-      test('test _getName', () => {
-        let account = {
+      test('test _getIdForUser', () => {
+        const account = {
           user: {
             username: 'test-user',
             _account_id: 12,
           },
         };
-        assert.equal(element._getNameForUser(account.user), 'test-user (12)');
-
-        account = {
-          user: {
-            name: 'test-name',
-            _account_id: 12,
-          },
-        };
-        assert.equal(element._getNameForUser(account.user), 'test-name (12)');
-
-        account = {
-          user: {
-            email: 'test-email@gmail.com',
-            _account_id: 12,
-          },
-        };
-        assert.equal(element._getNameForUser(account.user), 'test-email (12)');
+        assert.equal(element._getIdForUser(account.user), ' (12)');
       });
 
       test('test _account_id not present', () => {
-        let account = {
+        const account = {
           user: {
             username: 'test-user',
           },
         };
-        assert.equal(element._getNameForUser(account.user), 'test-user');
-
-        account = {
-          user: {
-            name: 'test-name',
-          },
-        };
-        assert.equal(element._getNameForUser(account.user), 'test-name');
-
-        account = {
-          user: {
-            email: 'test-email@gmail.com',
-          },
-        };
-        assert.equal(element._getNameForUser(account.user), 'test-email');
+        assert.equal(element._getIdForUser(account.user), '');
       });
     });
 
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html
index fa0fe52..fb8f6ec 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html
@@ -99,7 +99,7 @@
       }
       gr-dropdown {
         --gr-dropdown-item: {
-          color: var(--header-text-color);
+          color: var(--primary-text-color);
         }
       }
       .browse {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
index 0013d14..edee1ae 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
@@ -276,7 +276,7 @@
           </span>
         </div>
         <div class="rightControls">
-          <span class$="blameLoader [[_computeBlameLoaderClass(_isImageDiff, _isBlameSupported)]]">
+          <span class$="blameLoader [[_computeBlameLoaderClass(_isImageDiff)]]">
             <gr-button
                 link
                 disabled="[[_isBlameLoading]]"
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
index 5df640e..9c27bae 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
@@ -148,10 +148,6 @@
         type: Boolean,
         computed: '_computeEditMode(_patchRange.*)',
       },
-      _isBlameSupported: {
-        type: Boolean,
-        value: false,
-      },
       _isBlameLoaded: Boolean,
       _isBlameLoading: {
         type: Boolean,
@@ -203,10 +199,6 @@
         this._loggedIn = loggedIn;
       });
 
-      this.$.restAPI.getConfig().then(config => {
-        this._isBlameSupported = config.change.allow_blame;
-      });
-
       this.$.cursor.push('diffs', this.$.diff);
     },
 
@@ -972,8 +964,8 @@
           });
     },
 
-    _computeBlameLoaderClass(isImageDiff, supported) {
-      return !isImageDiff && supported ? 'show' : '';
+    _computeBlameLoaderClass(isImageDiff) {
+      return !isImageDiff ? 'show' : '';
     },
 
     _getRevisionInfo(change) {
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.html b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.html
index f6749b1..4b447d1 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.html
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.html
@@ -15,8 +15,8 @@
 limitations under the License.
 -->
 <link rel="import" href="../../../bower_components/polymer/polymer.html">
-<link rel="import" href="../../../bower_components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
 <link rel="import" href="../../../bower_components/paper-input/paper-input.html">
+<link rel="import" href="../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html">
 <link rel="import" href="../../shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.html">
 <link rel="import" href="../../shared/gr-cursor-manager/gr-cursor-manager.html">
 <link rel="import" href="../../shared/gr-icons/gr-icons.html">
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js
index f39398f..634bc00 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js
@@ -165,6 +165,10 @@
       _selected: Object,
     },
 
+    behaviors: [
+      Gerrit.KeyboardShortcutBehavior,
+    ],
+
     observers: [
       '_maybeOpenDropdown(_suggestions, _focused)',
       '_updateSuggestions(text, threshold, noDebounce)',
@@ -305,6 +309,7 @@
           }
           break;
         case 13: // Enter
+          if (this.modifierPressed(e)) { break; }
           e.preventDefault();
           this._handleInputCommit();
           break;
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html
index 2b0a081..585b16f 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html
@@ -496,6 +496,18 @@
       assert.isTrue(listener.called);
     });
 
+    test('enter with modifier does not complete', () => {
+      const handleSpy = sandbox.spy(element, '_handleKeydown');
+      const commitStub = sandbox.stub(element, '_handleInputCommit');
+      MockInteractions.pressAndReleaseKeyOn(
+          element.$.input, 13, 'ctrl', 'enter');
+      assert.isTrue(handleSpy.called);
+      assert.isFalse(commitStub.called);
+      MockInteractions.pressAndReleaseKeyOn(
+          element.$.input, 13, null, 'enter');
+      assert.isTrue(commitStub.called);
+    });
+
     suite('warnUncommitted', () => {
       let inputClassList;
       setup(() => {
diff --git a/resources/com/google/gerrit/pgm/Startup.py b/resources/com/google/gerrit/pgm/Startup.py
index cf6fac9..469d5df 100644
--- a/resources/com/google/gerrit/pgm/Startup.py
+++ b/resources/com/google/gerrit/pgm/Startup.py
@@ -16,6 +16,7 @@
 # Startup script for Gerrit Inspector - a Jython introspector
 # -----------------------------------------------------------------------
 
+from __future__ import print_function
 import sys
 
 def print_help():
@@ -23,9 +24,9 @@
     if not n.startswith("__") and not n in ['help', 'reload'] \
        and str(type(v)) != "<type 'javapackage'>"             \
        and not str(v).startswith("<module"):
-       print "\"%s\" is \"%s\"" % (n, v)
-  print
-  print "Welcome to the Gerrit Inspector"
-  print "Enter help() to see the above again, EOF to quit and stop Gerrit"
+       print("\"%s\" is \"%s\"" % (n, v))
+  print()
+  print("Welcome to the Gerrit Inspector")
+  print("Enter help() to see the above again, EOF to quit and stop Gerrit")
 
 print_help()