Merge "Remove rework check for dependencies in RebaseSorter"
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 59f45cf..b0a07c7 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -2325,6 +2325,14 @@
 +
 By default, true.
 
+[[httpd.inheritChannel]]httpd.inheritChannel::
++
+If true, permits the daemon to inherit its server socket channel
+from fd0/1(stdin/stdout). When set to true, the server can be socket
+activated via systemd or xinetd.
++
+By default, false.
+
 [[httpd.requestHeaderSize]]httpd.requestHeaderSize::
 +
 Size, in bytes, of the buffer used to parse the HTTP headers of an
diff --git a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java
index 5feb918..98d8d4c 100644
--- a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java
+++ b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java
@@ -16,12 +16,14 @@
 
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.gson.FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES;
+import static java.util.stream.Collectors.toList;
 import static org.apache.commons.codec.binary.Base64.decodeBase64;
 import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
 
 import com.google.common.base.Strings;
 import com.google.common.collect.FluentIterable;
 import com.google.common.collect.Iterables;
+import com.google.common.collect.Streams;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.gerrit.server.index.FieldDef.FillArgs;
@@ -183,15 +185,21 @@
     return new io.searchbox.core.Index.Builder(doc).index(indexName).type(type).id(id).build();
   }
 
+  private static boolean shouldAddElement(Object element) {
+    return !(element instanceof String) || !((String) element).isEmpty();
+  }
+
   private String toDoc(V v) throws IOException {
     XContentBuilder builder = jsonBuilder().startObject();
     for (Values<V> values : schema.buildFields(v, fillArgs)) {
       String name = values.getField().getName();
       if (values.getField().isRepeatable()) {
-        builder.array(name, values.getValues());
+        builder.field(
+            name,
+            Streams.stream(values.getValues()).filter(e -> shouldAddElement(e)).collect(toList()));
       } else {
         Object element = Iterables.getOnlyElement(values.getValues(), "");
-        if (!(element instanceof String) || !((String) element).isEmpty()) {
+        if (shouldAddElement(element)) {
           builder.field(name, element);
         }
       }
diff --git a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java
index 870b88a..77cae9b 100644
--- a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java
+++ b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java
@@ -354,20 +354,23 @@
           cd);
       decodeUnresolvedCommentCount(source, ChangeField.UNRESOLVED_COMMENT_COUNT.getName(), cd);
 
-      if (source.get(ChangeField.REF_STATE.getName()) != null) {
-        JsonArray refStates = source.get(ChangeField.REF_STATE.getName()).getAsJsonArray();
-        cd.setRefStates(Iterables.transform(refStates, e -> Base64.decodeBase64(e.getAsString())));
+      if (fields.contains(ChangeField.REF_STATE.getName())) {
+        cd.setRefStates(getByteArray(source, ChangeField.REF_STATE.getName()));
       }
-      if (source.get(ChangeField.REF_STATE_PATTERN.getName()) != null) {
-        JsonArray refStatePatterns =
-            source.get(ChangeField.REF_STATE_PATTERN.getName()).getAsJsonArray();
-        cd.setRefStatePatterns(
-            Iterables.transform(refStatePatterns, e -> Base64.decodeBase64(e.getAsString())));
+      if (fields.contains(ChangeField.REF_STATE_PATTERN.getName())) {
+        cd.setRefStatePatterns(getByteArray(source, ChangeField.REF_STATE_PATTERN.getName()));
       }
 
       return cd;
     }
 
+    private Iterable<byte[]> getByteArray(JsonObject source, String name) {
+      JsonElement element = source.get(name);
+      return element != null
+          ? Iterables.transform(element.getAsJsonArray(), e -> Base64.decodeBase64(e.getAsString()))
+          : Collections.emptyList();
+    }
+
     private void decodeSubmitRecords(
         JsonObject doc, String fieldName, SubmitRuleOptions opts, ChangeData out) {
       JsonArray records = doc.getAsJsonArray(fieldName);
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/JythonShell.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/JythonShell.java
index 0ca8db6..e740ec8 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/JythonShell.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/JythonShell.java
@@ -74,11 +74,11 @@
         pySystemState,
         pySystemState,
         "initialize",
-        new Class[] {Properties.class, Properties.class},
+        new Class<?>[] {Properties.class, Properties.class},
         new Object[] {null, env});
 
     try {
-      shell = console.getConstructor(new Class[] {}).newInstance();
+      shell = console.getConstructor(new Class<?>[] {}).newInstance();
       log.info("Jython shell instance created.");
     } catch (InstantiationException
         | IllegalAccessException
@@ -121,13 +121,13 @@
   }
 
   protected String getDefaultBanner() {
-    return (String) runInterpreter("getDefaultBanner", new Class[] {}, new Object[] {});
+    return (String) runInterpreter("getDefaultBanner", new Class<?>[] {}, new Object[] {});
   }
 
   protected void printInjectedVariable(String id) {
     runInterpreter(
         "exec",
-        new Class[] {String.class},
+        new Class<?>[] {String.class},
         new Object[] {"print '\"%s\" is \"%s\"' % (\"" + id + "\", " + id + ")"});
   }
 
@@ -138,7 +138,7 @@
     reload();
     runInterpreter(
         "interact",
-        new Class[] {String.class, pyObject},
+        new Class<?>[] {String.class, pyObject},
         new Object[] {
           getDefaultBanner()
               + " running for Gerrit "
@@ -148,7 +148,7 @@
   }
 
   public void set(String key, Object content) {
-    runInterpreter("set", new Class[] {String.class, Object.class}, new Object[] {key, content});
+    runInterpreter("set", new Class<?>[] {String.class, Object.class}, new Object[] {key, content});
     injectedVariables.add(key);
   }
 
@@ -185,7 +185,7 @@
             console,
             shell,
             "execfile",
-            new Class[] {String.class},
+            new Class<?>[] {String.class},
             new Object[] {script.getAbsolutePath()});
       } else {
         log.info(
@@ -206,7 +206,7 @@
           console,
           shell,
           "execfile",
-          new Class[] {InputStream.class, String.class},
+          new Class<?>[] {InputStream.class, String.class},
           new Object[] {in, p});
     } catch (InvocationTargetException e) {
       log.error("Exception occurred while loading " + p + " : ", e);
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyServer.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyServer.java
index 90f8558..38c3321 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyServer.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyServer.java
@@ -275,7 +275,7 @@
       } catch (URISyntaxException e) {
         throw new IllegalArgumentException("Invalid httpd.listenurl " + u, e);
       }
-
+      c.setInheritChannel(cfg.getBoolean("httpd", "inheritChannel", false));
       c.setReuseAddress(reuseAddress);
       connectors[idx] = c;
     }
diff --git a/gerrit-pgm/src/main/resources/com/google/gerrit/pgm/systemd/gerrit.service b/gerrit-pgm/src/main/resources/com/google/gerrit/pgm/systemd/gerrit.service
new file mode 100644
index 0000000..750dbb4
--- /dev/null
+++ b/gerrit-pgm/src/main/resources/com/google/gerrit/pgm/systemd/gerrit.service
@@ -0,0 +1,17 @@
+# Systemd unit file for gerrit
+
+[Unit]
+Description=Gerrit Code Review
+After=syslog.target network.target
+
+[Service]
+Type=simple
+WorkingDirectory=/opt/gerritsrv/
+Environment=GERRIT_HOME=/opt/gerritsrv/gerrit/ JAVA_HOME=/opt/jdk1.8.0_45/
+ExecStart=/usr/bin/java -Xmx1024m -jar ${GERRIT_HOME}/bin/gerrit.war daemon -d ${GERRIT_HOME}
+User=gerritsrv
+SyslogIdentifier=GerritCodeReview
+StandardInput=socket
+
+[Install]
+WantedBy=multi-user.target
diff --git a/gerrit-pgm/src/main/resources/com/google/gerrit/pgm/systemd/gerrit.socket b/gerrit-pgm/src/main/resources/com/google/gerrit/pgm/systemd/gerrit.socket
new file mode 100644
index 0000000..cee5d12
--- /dev/null
+++ b/gerrit-pgm/src/main/resources/com/google/gerrit/pgm/systemd/gerrit.socket
@@ -0,0 +1,9 @@
+[Unit]
+Description=Gerrit HTTP socket
+
+[Socket]
+ListenStream=80
+Accept=no
+
+[Install]
+WantedBy=sockets.target
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/ExternalId.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/ExternalId.java
index 45129e3..d057f56 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/ExternalId.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/ExternalId.java
@@ -27,6 +27,7 @@
 import com.google.gerrit.extensions.client.AuthType;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.AccountExternalId;
+import java.io.Serializable;
 import java.util.Collection;
 import java.util.Set;
 import org.eclipse.jgit.errors.ConfigInvalidException;
@@ -34,7 +35,9 @@
 import org.eclipse.jgit.lib.ObjectId;
 
 @AutoValue
-public abstract class ExternalId {
+public abstract class ExternalId implements Serializable {
+  private static final long serialVersionUID = 1L;
+
   private static final String EXTERNAL_ID_SECTION = "externalId";
   private static final String ACCOUNT_ID_KEY = "accountId";
   private static final String EMAIL_KEY = "email";
@@ -64,7 +67,9 @@
   public static final String SCHEME_EXTERNAL = "external";
 
   @AutoValue
-  public abstract static class Key {
+  public abstract static class Key implements Serializable {
+    private static final long serialVersionUID = 1L;
+
     public static Key create(@Nullable String scheme, String id) {
       return new AutoValue_ExternalId_Key(scheme, id);
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/SearchingChangeCacheImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/SearchingChangeCacheImpl.java
index 947382b..abce2d2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/SearchingChangeCacheImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/SearchingChangeCacheImpl.java
@@ -30,6 +30,7 @@
 import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gerrit.server.query.change.InternalChangeQuery;
+import com.google.gerrit.server.util.ManualRequestContext;
 import com.google.gerrit.server.util.OneOffRequestContext;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -144,7 +145,7 @@
 
     @Override
     public List<CachedChange> load(Project.NameKey key) throws Exception {
-      try (AutoCloseable ctx = requestContext.open()) {
+      try (ManualRequestContext ctx = requestContext.open()) {
         List<ChangeData> cds =
             queryProvider
                 .get()
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/NoteDbUpdateManager.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/NoteDbUpdateManager.java
index 9504564..b7bcafa 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/NoteDbUpdateManager.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/NoteDbUpdateManager.java
@@ -38,6 +38,7 @@
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.InMemoryInserter;
 import com.google.gerrit.server.git.InsertedObject;
+import com.google.gerrit.server.git.LockFailureException;
 import com.google.gerrit.server.notedb.NoteDbChangeState.PrimaryStorage;
 import com.google.gerrit.server.update.ChainedReceiveCommands;
 import com.google.gwtorm.server.OrmConcurrencyException;
@@ -476,11 +477,18 @@
     or.cmds.addTo(bru);
     bru.setAllowNonFastForwards(true);
     bru.execute(or.rw, NullProgressMonitor.INSTANCE);
+
+    boolean lockFailure = false;
     for (ReceiveCommand cmd : bru.getCommands()) {
-      if (cmd.getResult() != ReceiveCommand.Result.OK) {
+      if (cmd.getResult() == ReceiveCommand.Result.LOCK_FAILURE) {
+        lockFailure = true;
+      } else if (cmd.getResult() != ReceiveCommand.Result.OK) {
         throw new IOException("Update failed: " + bru);
       }
     }
+    if (lockFailure) {
+      throw new LockFailureException("Update failed with one or more lock failures: " + bru);
+    }
   }
 
   private void addCommands() throws OrmException, IOException {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/update/ReviewDbBatchUpdate.java b/gerrit-server/src/main/java/com/google/gerrit/server/update/ReviewDbBatchUpdate.java
index 05fbbca..37a25af 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/update/ReviewDbBatchUpdate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/update/ReviewDbBatchUpdate.java
@@ -49,6 +49,7 @@
 import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.InsertedObject;
+import com.google.gerrit.server.git.LockFailureException;
 import com.google.gerrit.server.index.change.ChangeIndexer;
 import com.google.gerrit.server.notedb.ChangeNotes;
 import com.google.gerrit.server.notedb.ChangeUpdate;
@@ -84,7 +85,6 @@
 import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.NullProgressMonitor;
 import org.eclipse.jgit.lib.ObjectInserter;
-import org.eclipse.jgit.lib.ObjectReader;
 import org.eclipse.jgit.lib.PersonIdent;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.RevWalk;
@@ -561,7 +561,8 @@
     }
   }
 
-  private void executeNoteDbUpdates(List<ChangeTask> tasks) throws IOException {
+  private void executeNoteDbUpdates(List<ChangeTask> tasks)
+      throws ResourceConflictException, IOException {
     // Aggregate together all NoteDb ref updates from the ops we executed,
     // possibly in parallel. Each task had its own NoteDbUpdateManager instance
     // with its own thread-local copy of the repo(s), but each of those was just
@@ -624,18 +625,21 @@
       }
     } catch (IOException e) {
       if (tasks.stream().allMatch(t -> t.storage == PrimaryStorage.REVIEW_DB)) {
-        // Ignore all errors trying to update NoteDb at this point. We've
-        // already written the NoteDbChangeStates to ReviewDb, which means
-        // if any state is out of date it will be rebuilt the next time it
-        // is needed.
+        // Ignore all errors trying to update NoteDb at this point. We've already written the
+        // NoteDbChangeStates to ReviewDb, which means if any state is out of date it will be
+        // rebuilt the next time it is needed.
+        //
         // Always log even without RequestId.
         log.debug("Ignoring NoteDb update error after ReviewDb write", e);
-      } else {
-        // We can't prove it's safe to ignore the error, either because some
-        // change had NOTE_DB primary, or a task failed before determining the
-        // primary storage.
-        throw e;
+
+        // Otherwise, we can't prove it's safe to ignore the error, either because some change had
+        // NOTE_DB primary, or a task failed before determining the primary storage.
+      } else if (e instanceof LockFailureException) {
+        // LOCK_FAILURE is a special case indicating there was a conflicting write to a meta ref,
+        // although it happened too late for us to produce anything but a generic error message.
+        throw new ResourceConflictException("Updating change failed due to conflicting write", e);
       }
+      throw e;
     }
   }
 
@@ -681,8 +685,7 @@
       taskId = id.toString() + "-" + Thread.currentThread().getId();
       if (Thread.currentThread() == mainThread) {
         Repository repo = getRepository();
-        try (ObjectReader reader = repo.newObjectReader();
-            RevWalk rw = new RevWalk(repo)) {
+        try (RevWalk rw = new RevWalk(repo)) {
           call(ReviewDbBatchUpdate.this.db, repo, rw);
         }
       } else {
diff --git a/gerrit-server/src/main/resources/com/google/gerrit/server/mail/ReplacePatchSet.soy b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/ReplacePatchSet.soy
index 93c1c3b..e41bdda 100644
--- a/gerrit-server/src/main/resources/com/google/gerrit/server/mail/ReplacePatchSet.soy
+++ b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/ReplacePatchSet.soy
@@ -60,11 +60,4 @@
         {$patchSet.refName}
     {\n}
   {/if}
-
-  {if $email.includeDiff}
-    {\n}
-    {\n}
-    {$email.unifiedDiff}
-    {\n}
-  {/if}
 {/template}
\ No newline at end of file
diff --git a/gerrit-server/src/main/resources/com/google/gerrit/server/mail/ReplacePatchSetHtml.soy b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/ReplacePatchSetHtml.soy
index 23a7630..05c60a1 100644
--- a/gerrit-server/src/main/resources/com/google/gerrit/server/mail/ReplacePatchSetHtml.soy
+++ b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/ReplacePatchSetHtml.soy
@@ -49,8 +49,4 @@
           {$patchSet.refName}
     {/param}{/call}
   {/if}
-
-  {if $email.includeDiff}
-    {call .Pre}{param content: $email.unifiedDiff /}{/call}
-  {/if}
 {/template}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/plugin/LfsPluginAuthCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/plugin/LfsPluginAuthCommand.java
index 0ade137..b44f0fc 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/plugin/LfsPluginAuthCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/plugin/LfsPluginAuthCommand.java
@@ -25,8 +25,14 @@
 import java.util.List;
 import org.eclipse.jgit.lib.Config;
 import org.kohsuke.args4j.Argument;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class LfsPluginAuthCommand extends SshCommand {
+  private static final Logger log = LoggerFactory.getLogger(LfsPluginAuthCommand.class);
+  private static final String CONFIGURATION_ERROR =
+      "Server configuration error: LFS auth over SSH is not properly configured.";
+
   public interface LfsSshPluginAuth {
     String authenticate(CurrentUser user, List<String> args) throws UnloggedFailure, Failure;
   }
@@ -61,11 +67,11 @@
   }
 
   @Override
-  protected void run() throws UnloggedFailure, Failure, Exception {
+  protected void run() throws UnloggedFailure, Exception {
     LfsSshPluginAuth pluginAuth = auth.get();
     if (pluginAuth == null) {
-      throw new Failure(
-          1, "Server configuration error: LFS auth over SSH is not properly configured.");
+      log.warn(CONFIGURATION_ERROR);
+      throw new UnloggedFailure(1, CONFIGURATION_ERROR);
     }
 
     stdout.print(pluginAuth.authenticate(user.get(), args));
diff --git a/plugins/hooks b/plugins/hooks
index a329746..60adf57 160000
--- a/plugins/hooks
+++ b/plugins/hooks
@@ -1 +1 @@
-Subproject commit a32974634954aa904acc00644bb0beb58b1ea934
+Subproject commit 60adf5742f44badc5193b42ffc841bb2d0f6e442
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.html b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.html
index 0dee091..527485d 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.html
+++ b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.html
@@ -15,38 +15,11 @@
 -->
 
 <link rel="import" href="../../../bower_components/polymer/polymer.html">
+<link rel="import" href="../../shared/gr-placeholder/gr-placeholder.html">
 
 <dom-module id="gr-admin-view">
   <template>
-    <style>
-      main {
-        margin: 2em auto;
-        max-width: 46em;
-      }
-      h1 {
-        margin-bottom: .1em;
-      }
-      @media only screen and (max-width: 67em) {
-        main {
-          margin: 2em 0 2em 15em;
-        }
-      }
-      @media only screen and (max-width: 53em) {
-        .loading {
-          padding: 0 var(--default-horizontal-margin);
-        }
-        main {
-          margin: 2em 1em;
-        }
-    </style>
-    <main>
-      <h1>Admin</h1>
-      <section>
-        This page is not yet implemented in PolyGerrit. View it in the
-        <a id="gwtLink" href$="/?polygerrit=0#[[path]]" rel="external">
-        Old UI</a>
-      </section>
-    </main>
+    <gr-placeholder title="Admin" path="[[path]]"></gr-placeholder>
   </template>
   <script src="gr-admin-view.js"></script>
 </dom-module>
diff --git a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.js b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.js
index 1adfb01..577b983 100644
--- a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.js
+++ b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.js
@@ -38,7 +38,7 @@
       var diffURL = this._computeFileDiffURL(file, changeNum, patchNum);
       if (comment.line) {
         diffURL += '#';
-        if (comment.side === 'PARENT') { diffURL += 'b'; }
+        if (comment.__isOnParent) { diffURL += 'b'; }
         diffURL += comment.line;
       }
       return diffURL;
@@ -51,7 +51,7 @@
     },
 
     _computePatchDisplayName: function(comment) {
-      if (comment.side == 'PARENT') {
+      if (comment.__isOnParent) {
         return 'Base, ';
       }
       if (comment.patch_set != this.patchNum) {
diff --git a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list_test.html b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list_test.html
index a132d43..0f4344c 100644
--- a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list_test.html
@@ -71,7 +71,7 @@
       assert.equal(actual, expected);
 
       comment.line = 321;
-      comment.side = 'PARENT';
+      comment.__isOnParent = true;
 
       expected = '/c/<change>/<patch>/<file>#b321';
       actual = element._computeDiffLineURL('<file>', '<change>', '<patch>',
@@ -87,7 +87,7 @@
       element.patchNum = 9;
       assert.equal(element._computePatchDisplayName(comment), 'PS10, ');
 
-      comment.side = 'PARENT';
+      comment.__isOnParent = true;
       assert.equal(element._computePatchDisplayName(comment), 'Base, ');
     });
   });
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html
index 0a02e08..a88e0eb 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html
@@ -311,7 +311,7 @@
       </div>
       <gr-diff
           no-auto-render
-          hidden$="[[!_isFileExpanded(file.__path, _expandedFilePaths.*)]]"
+          hidden="[[!_isFileExpanded(file.__path, _expandedFilePaths.*)]]"
           project="[[change.project]]"
           commit="[[change.current_revision]]"
           change-num="[[changeNum]]"
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
index 0f8e1b3..4be2ca7 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
@@ -240,6 +240,10 @@
       }
     },
 
+    _togglePathExpandedByIndex: function(index) {
+      this._togglePathExpanded(this._files[index].__path);
+    },
+
     _handlePatchChange: function(e) {
       var patchRange = Object.assign({}, this.patchRange);
       patchRange.basePatchNum = Polymer.dom(e).rootTarget.value;
@@ -430,7 +434,7 @@
           this.$.fileCursor.index === -1) { return; }
 
       e.preventDefault();
-      this._togglePathExpanded(this.$.fileCursor.target.path);
+      this._togglePathExpandedByIndex(this.$.fileCursor.index);
     },
 
     _handleCapitalIKey: function(e) {
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router.js b/polygerrit-ui/app/elements/core/gr-router/gr-router.js
index d8f9c32..eb650ca 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router.js
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.js
@@ -198,6 +198,17 @@
       app.params = params;
     });
 
+    page(/^\/settings\/(agreements|new-agreement)/, loadUser, function(data) {
+      restAPI.getLoggedIn().then(function(loggedIn) {
+        if (loggedIn) {
+          data.params.view = 'gr-cla-view';
+          app.params = data.params;
+        } else {
+          page.redirect('/login/' + encodeURIComponent(data.canonicalPath));
+        }
+      });
+    });
+
     page(/^\/settings\/VE\/(\S+)/, function(data) {
       restAPI.getLoggedIn().then(function(loggedIn) {
         if (loggedIn) {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html
index a2b4b0d..a936934 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html
@@ -216,10 +216,10 @@
               GrDiffBuilder.Side.RIGHT : GrDiffBuilder.Side.LEFT;
         },
 
-        createCommentThreadGroup: function(changeNum, patchNum, path, side,
-            commentSide, projectConfig) {
+        createCommentThreadGroup: function(changeNum, patchNum, path,
+            isOnParent, commentSide, projectConfig) {
           return this._builder.createCommentThreadGroup(changeNum, patchNum,
-              path, side, commentSide, projectConfig);
+              path, isOnParent, commentSide, projectConfig);
         },
 
         emitGroup: function(group, sectionEl) {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.js b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.js
index 54a72f6..379e9f9 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.js
@@ -336,13 +336,13 @@
   };
 
   GrDiffBuilder.prototype.createCommentThreadGroup = function(changeNum,
-      patchNum, path, side, projectConfig, range) {
+      patchNum, path, isOnParent, projectConfig, range) {
     var threadGroupEl =
         document.createElement('gr-diff-comment-thread-group');
     threadGroupEl.changeNum = changeNum;
     threadGroupEl.patchForNewThreads = patchNum;
     threadGroupEl.path = path;
-    threadGroupEl.side = side;
+    threadGroupEl.isOnParent = isOnParent;
     threadGroupEl.projectConfig = projectConfig;
     threadGroupEl.range = range;
     return threadGroupEl;
@@ -356,11 +356,11 @@
     }
 
     var patchNum = this._comments.meta.patchRange.patchNum;
-    var side = comments[0].side || 'REVISION';
+    var isOnParent = comments[0].__isOnParent || false ;
     if (line.type === GrDiffLine.Type.REMOVE ||
         opt_side === GrDiffBuilder.Side.LEFT) {
       if (this._comments.meta.patchRange.basePatchNum === 'PARENT') {
-        side = 'PARENT';
+        isOnParent = true;
       } else {
         patchNum = this._comments.meta.patchRange.basePatchNum;
       }
@@ -369,7 +369,7 @@
         this._comments.meta.changeNum,
         patchNum,
         this._comments.meta.path,
-        side,
+        isOnParent,
         this._comments.meta.projectConfig);
     threadGroupEl.comments = comments;
     if (opt_side) {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html
index 566d462..d53929e 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html
@@ -255,11 +255,12 @@
         right: [r5],
       };
 
-      function checkThreadGroupProps(threadGroupEl, patchNum, side, comments) {
+      function checkThreadGroupProps(threadGroupEl, patchNum, isOnParent,
+          comments) {
         assert.equal(threadGroupEl.changeNum, '42');
         assert.equal(threadGroupEl.patchForNewThreads, patchNum);
         assert.equal(threadGroupEl.path, '/path/to/foo');
-        assert.equal(threadGroupEl.side, side);
+        assert.equal(threadGroupEl.isOnParent, isOnParent);
         assert.deepEqual(threadGroupEl.projectConfig, {foo: 'bar'});
         assert.deepEqual(threadGroupEl.comments, comments);
       }
@@ -268,28 +269,28 @@
       line.beforeNumber = 5;
       line.afterNumber = 5;
       var threadGroupEl = builder._commentThreadGroupForLine(line);
-      checkThreadGroupProps(threadGroupEl, '3', 'REVISION', [l5, r5]);
+      checkThreadGroupProps(threadGroupEl, '3', false, [l5, r5]);
 
       threadGroupEl =
           builder._commentThreadGroupForLine(line, GrDiffBuilder.Side.RIGHT);
-      checkThreadGroupProps(threadGroupEl, '3', 'REVISION', [r5]);
+      checkThreadGroupProps(threadGroupEl, '3', false, [r5]);
 
       threadGroupEl =
           builder._commentThreadGroupForLine(line, GrDiffBuilder.Side.LEFT);
-      checkThreadGroupProps(threadGroupEl, '3', 'PARENT', [l5]);
+      checkThreadGroupProps(threadGroupEl, '3', true, [l5]);
 
       builder._comments.meta.patchRange.basePatchNum = '1';
 
       threadGroupEl = builder._commentThreadGroupForLine(line);
-      checkThreadGroupProps(threadGroupEl, '3', 'REVISION', [l5, r5]);
+      checkThreadGroupProps(threadGroupEl, '3', false, [l5, r5]);
 
       threadEl =
           builder._commentThreadGroupForLine(line, GrDiffBuilder.Side.LEFT);
-      checkThreadGroupProps(threadEl, '1', 'REVISION', [l5]);
+      checkThreadGroupProps(threadEl, '1', false, [l5]);
 
       threadGroupEl =
           builder._commentThreadGroupForLine(line, GrDiffBuilder.Side.RIGHT);
-      checkThreadGroupProps(threadGroupEl, '3', 'REVISION', [r5]);
+      checkThreadGroupProps(threadGroupEl, '3', false, [r5]);
 
       builder._comments.meta.patchRange.basePatchNum = 'PARENT';
 
@@ -297,13 +298,13 @@
       line.beforeNumber = 5;
       line.afterNumber = 5;
       threadGroupEl = builder._commentThreadGroupForLine(line);
-      checkThreadGroupProps(threadGroupEl, '3', 'PARENT', [l5, r5]);
+      checkThreadGroupProps(threadGroupEl, '3', true, [l5, r5]);
 
       line = new GrDiffLine(GrDiffLine.Type.ADD);
       line.beforeNumber = 3;
       line.afterNumber = 5;
       threadGroupEl = builder._commentThreadGroupForLine(line);
-      checkThreadGroupProps(threadGroupEl, '3', 'REVISION', [l3, r5]);
+    checkThreadGroupProps(threadGroupEl, '3', false, [l3, r5]);
     });
 
     suite('_isTotal', function() {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.html b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.html
index 95de61f..30dfacf 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.html
@@ -33,11 +33,11 @@
       <gr-diff-comment-thread
           comments="[[thread.comments]]"
           comment-side="[[thread.commentSide]]"
+          is-on-parent="[[isOnParent]]"
           change-num="[[changeNum]]"
           location-range="[[thread.locationRange]]"
           patch-num="[[thread.patchNum]]"
           path="[[path]]"
-          side="[[side]]"
           project-config="[[projectConfig]]"></gr-diff-comment-thread>
     </template>
   </template>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.js b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.js
index ee4c5b3..df75d52 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.js
@@ -26,9 +26,9 @@
       patchForNewThreads: String,
       projectConfig: Object,
       range: Object,
-      side: {
-        type: String,
-        value: 'REVISION',
+      isOnParent: {
+        type: Boolean,
+        value: false,
       },
       _threads: {
         type: Array,
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.html b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.html
index a86d957..258b6fd 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.html
@@ -59,7 +59,7 @@
             draft="[[comment.__draft]]"
             show-actions="[[_showActions]]"
             comment-side="[[comment.__commentSide]]"
-            side="[[side]]"
+            is-on-parent="[[isOnParent]]"
             project-config="[[projectConfig]]"
             on-create-fix-comment="_handleCommentFix"
             on-comment-discard="_handleCommentDiscard"></gr-diff-comment>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.js b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.js
index 81c2752..00c3277 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.js
@@ -41,9 +41,9 @@
       patchNum: String,
       path: String,
       projectConfig: Object,
-      side: {
-        type: String,
-        value: 'REVISION',
+      isOnParent: {
+        type: Boolean,
+        value: false,
       },
 
       _showActions: Boolean,
@@ -272,7 +272,7 @@
         __date: new Date(),
         path: this.path,
         patchNum: this.patchNum,
-        side: this.side,
+        __isOnParent: this.__isOnParent,
         __commentSide: this.commentSide,
       };
       if (opt_lineNum) {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js
index 43d7c3e..c49191b 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js
@@ -139,6 +139,10 @@
 
     save: function() {
       this.comment.message = this._messageText;
+
+      // Translate {Boolean} __isOnParent to {String} side for the REST API
+      // format.
+      this.comment.side = this.comment.__isOnParent ? 'PARENT' : null;
       this.disabled = true;
 
       this._eraseDraftComment();
@@ -149,6 +153,7 @@
 
         return this.$.restAPI.getResponseObject(response).then(function(obj) {
           var comment = obj;
+          comment.__isOnParent = comment.side === 'PARENT';
           comment.__draft = true;
           // Maintain the ephemeral draft ID for identification by other
           // elements.
@@ -402,16 +407,18 @@
     },
 
     _saveDraft: function(draft) {
+      draft.side = draft.__isOnParent ? 'PARENT' : null;
       return this.$.restAPI.saveDiffDraft(this.changeNum, this.patchNum, draft);
     },
 
     _deleteDraft: function(draft) {
+      draft.side = draft.__isOnParent ? 'PARENT' : null;
       return this.$.restAPI.deleteDiffDraft(this.changeNum, this.patchNum,
           draft);
     },
 
     _getPatchNum: function() {
-      return this.side === 'PARENT' ? 'PARENT' : this.patchNum;
+      return this.isOnParent ? 'PARENT' : this.patchNum;
     },
 
     _loadLocalDraft: function(changeNum, patchNum, comment) {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html
index 2881fc1..d3faf76 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html
@@ -153,10 +153,10 @@
     });
 
     test('_getPatchNum', function() {
-      element.side = 'PARENT';
+      element.isOnParent = true;
       element.patchNum = 1;
       assert.equal(element._getPatchNum(), 'PARENT');
-      element.side = 'REVISION';
+      element.isOnParent = false;
       assert.equal(element._getPatchNum(), 1);
     });
 
@@ -508,6 +508,7 @@
         assert.deepEqual(fireStub.lastCall.args[1], {
           comment: {
             __commentSide: 'right',
+            __isOnParent: false,
             __draft: true,
             __draftID: 'temp_draft_id',
             __editing: false,
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.html b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.html
index c39a89f..fe57c43 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.html
@@ -87,7 +87,7 @@
         </select>
       </div>
       <div class="pref">
-        <label for="lineWrappingInput">Fit to Screen</label>
+        <label for="lineWrappingInput">Fit to screen</label>
         <input
             is="iron-input"
             type="checkbox"
@@ -95,7 +95,7 @@
             on-tap="_handlelineWrappingTap">
       </div>
       <div class="pref" id="columnsPref" hidden$="[[_newPrefs.line_wrapping]]">
-        <label for="columnsInput">Diff Width</label>
+        <label for="columnsInput">Diff width</label>
         <input is="iron-input" type="number" id="columnsInput"
             prevent-invalid-input
             allowed-pattern="[0-9]"
@@ -109,7 +109,7 @@
             bind-value="{{_newPrefs.tab_size}}">
       </div>
       <div class="pref" hidden$="[[!_newPrefs.font_size]]">
-        <label for="fontSizeInput">Font Size</label>
+        <label for="fontSizeInput">Font size</label>
         <input is="iron-input" type="number" id="fontSizeInput"
                prevent-invalid-input
                allowed-pattern="[0-9]"
@@ -121,7 +121,7 @@
             on-tap="_handleShowTabsTap">
       </div>
       <div class="pref">
-        <label for="showTrailingWhitespaceInput">Show Trailing Whitespace</label>
+        <label for="showTrailingWhitespaceInput">Show trailing whitespace</label>
         <input is="iron-input" type="checkbox" id="showTrailingWhitespaceInput"
             on-tap="_handleShowTrailingWhitespaceTap">
       </div>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
index a5147f1..05a7f72 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
@@ -64,7 +64,10 @@
         value: function() { return {}; },
         notify: true,
       },
-
+      hidden: {
+        type: Boolean,
+        reflectToAttribute: true,
+      },
       _loggedIn: {
         type: Boolean,
         value: false,
@@ -133,7 +136,7 @@
     },
 
     getCursorStops: function() {
-      if (this.noAutoRender) {
+      if (this.hidden && this.noAutoRender) {
         return [];
       }
 
@@ -226,9 +229,10 @@
       var contentText = this.$.diffBuilder.getContentByLineEl(lineEl);
       var contentEl = contentText.parentElement;
       var patchNum = this._getPatchNumByLineAndContent(lineEl, contentEl);
-      var side = this._getSideByLineAndContent(lineEl, contentEl);
+      var isOnParent =
+          this._getIsParentCommentByLineAndContent(lineEl, contentEl);
       var threadEl = this._getOrCreateThreadAtLineRange(contentEl, patchNum,
-          diffSide, side, range);
+          diffSide, isOnParent, range);
 
       threadEl.addOrEditDraft(line, range);
     },
@@ -238,9 +242,10 @@
       var contentEl = contentText.parentElement;
       var patchNum = this._getPatchNumByLineAndContent(lineEl, contentEl);
       var commentSide = this._getCommentSideByLineAndContent(lineEl, contentEl);
-      var side = this._getSideByLineAndContent(lineEl, contentEl);
+      var isOnParent =
+          this._getIsParentCommentByLineAndContent(lineEl, contentEl);
       var threadEl = this._getOrCreateThreadAtLineRange(contentEl, patchNum,
-          commentSide, side);
+          commentSide, isOnParent);
 
       threadEl.addOrEditDraft(opt_lineNum);
     },
@@ -254,7 +259,7 @@
     },
 
     _getOrCreateThreadAtLineRange:
-        function(contentEl, patchNum, commentSide, side, range) {
+        function(contentEl, patchNum, commentSide, isOnParent, range) {
       var rangeToCheck = range ?
           'range-' +
           range.startLine + '-' +
@@ -267,7 +272,7 @@
       var threadGroupEl = this._getThreadGroupForLine(contentEl);
       if (!threadGroupEl) {
         threadGroupEl = this.$.diffBuilder.createCommentThreadGroup(
-          this.changeNum, patchNum, this.path, side,
+          this.changeNum, patchNum, this.path, isOnParent,
           this.projectConfig);
         contentEl.appendChild(threadGroupEl);
       }
@@ -293,14 +298,14 @@
       return patchNum;
     },
 
-    _getSideByLineAndContent: function(lineEl, contentEl) {
-      var side = 'REVISION';
+    _getIsParentCommentByLineAndContent: function(lineEl, contentEl) {
+      var isOnParent = false;
       if ((lineEl.classList.contains(DiffSide.LEFT) ||
           contentEl.classList.contains('remove')) &&
           this.patchRange.basePatchNum === 'PARENT') {
-        side = 'PARENT';
+        isOnParent = true;
       }
-      return side;
+      return isOnParent;
     },
 
     _getCommentSideByLineAndContent: function(lineEl, contentEl) {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
index 117ff24..9288e92 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
@@ -23,6 +23,7 @@
 <script src="../../../scripts/util.js"></script>
 
 <link rel="import" href="../../../bower_components/iron-test-helpers/iron-test-helpers.html">
+<link rel="import" href="../../shared/gr-rest-api-interface/mock-diff-response_test.html">
 <link rel="import" href="gr-diff.html">
 
 <test-fixture id="basic">
@@ -422,6 +423,50 @@
         element.path = 'file.txt';
         element._getDiff().then(done);
       });
+
+      suite('getCursorStops', function() {
+
+        var setupDiff = function() {
+          var mock = document.createElement('mock-diff-response');
+          element._diff = mock.diffResponse;
+          element._comments = {
+            left: [],
+            right: [],
+          };
+          element.prefs = {
+            context: 10,
+            tab_size: 8,
+            font_size: 12,
+            line_length: 100,
+            cursor_blink_rate: 0,
+            line_wrapping: false,
+            intraline_difference: true,
+            show_line_endings: true,
+            show_tabs: true,
+            show_whitespace_errors: true,
+            syntax_highlighting: true,
+            auto_hide_diff_table_header: true,
+            theme: 'DEFAULT',
+            ignore_whitespace: 'IGNORE_NONE',
+          };
+
+          element._renderDiffTable();
+          flushAsynchronousOperations();
+        };
+
+        test('getCursorStops returns [] when hidden and noAutoRender are true',
+             function() {
+          element.noAutoRender = true;
+          setupDiff();
+          element.hidden = true;
+          assert.equal(element.getCursorStops().length, 0);
+        });
+
+        test('getCursorStops', function() {
+          setupDiff();
+          assert.equal(element.getCursorStops().length, 50);
+        });
+      });
     });
 
     suite('logged in', function() {
diff --git a/polygerrit-ui/app/elements/gr-app.html b/polygerrit-ui/app/elements/gr-app.html
index aa66986..3af9535 100644
--- a/polygerrit-ui/app/elements/gr-app.html
+++ b/polygerrit-ui/app/elements/gr-app.html
@@ -30,6 +30,7 @@
 <link rel="import" href="./change-list/gr-dashboard-view/gr-dashboard-view.html">
 <link rel="import" href="./change/gr-change-view/gr-change-view.html">
 <link rel="import" href="./diff/gr-diff-view/gr-diff-view.html">
+<link rel="import" href="./settings/gr-cla-view/gr-cla-view.html">
 <link rel="import" href="./settings/gr-registration-dialog/gr-registration-dialog.html">
 <link rel="import" href="./settings/gr-settings-view/gr-settings-view.html">
 
@@ -128,6 +129,9 @@
       <template is="dom-if" if="[[_showAdminView]]" restamp="true">
         <gr-admin-view path="[[_path]]"></gr-admin-view>
       </template>
+      <template is="dom-if" if="[[_showCLAView]]" restamp="true">
+        <gr-cla-view path="[[_path]]"></gr-cla-view>
+      </template>
       <div id="errorView" class="errorView" hidden>
         <div class="errorEmoji">[[_lastError.emoji]]</div>
         <div class="errorText">[[_lastError.text]]</div>
diff --git a/polygerrit-ui/app/elements/gr-app.js b/polygerrit-ui/app/elements/gr-app.js
index 82c71be..0874b5d 100644
--- a/polygerrit-ui/app/elements/gr-app.js
+++ b/polygerrit-ui/app/elements/gr-app.js
@@ -121,6 +121,7 @@
       this.set('_showDiffView', view === 'gr-diff-view');
       this.set('_showSettingsView', view === 'gr-settings-view');
       this.set('_showAdminView', view === 'gr-admin-view');
+      this.set('_showCLAView', view === 'gr-cla-view');
       if (this.params.justRegistered) {
         this.$.registration.open();
       }
diff --git a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.html b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.html
index defcf18..0c61998 100644
--- a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.html
+++ b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.html
@@ -46,7 +46,7 @@
         <span class="value">[[_account.username]]</span>
       </section>
       <section id="nameSection">
-        <span class="title">Full Name</span>
+        <span class="title">Full name</span>
         <span
             hidden$="[[mutable]]"
             class="value">[[_account.name]]</span>
diff --git a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.html b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.html
new file mode 100644
index 0000000..b667d66
--- /dev/null
+++ b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.html
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<link rel="import" href="../../../bower_components/polymer/polymer.html">
+<link rel="import" href="../../shared/gr-placeholder/gr-placeholder.html">
+
+<dom-module id="gr-cla-view">
+  <template>
+    <gr-placeholder title="Agreements" path="[[path]]"></gr-placeholder>
+  </template>
+  <script src="gr-cla-view.js"></script>
+</dom-module>
diff --git a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.js b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.js
new file mode 100644
index 0000000..71dc71b
--- /dev/null
+++ b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.js
@@ -0,0 +1,24 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+(function() {
+  'use strict';
+
+  Polymer({
+    is: 'gr-cla-view',
+
+    properties: {
+      path: String,
+    },
+  });
+})();
diff --git a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.html b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.html
index d68cc33..303d836 100644
--- a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.html
+++ b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.html
@@ -39,7 +39,7 @@
           <tr>
             <th class="nameHeader">Name</th>
             <th class="descriptionHeader">Description</th>
-            <th>Visible to All</th>
+            <th>Visible to all</th>
           </tr>
         </thead>
         <tbody>
diff --git a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.html b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.html
index d96237e..e01ab94 100644
--- a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.html
+++ b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.html
@@ -48,13 +48,20 @@
     </style>
     <style include="gr-settings-styles"></style>
     <div class="gr-settings-styles">
-      <section>
-        <span class="title">Username</span>
-        <span class="value">[[_username]]</span>
-      </section>
-      <gr-button
-          id="generateButton"
-          on-tap="_handleGenerateTap">Generate New Password</gr-button>
+      <div hidden$="[[_passwordUrl]]">
+        <section>
+          <span class="title">Username</span>
+          <span class="value">[[_username]]</span>
+        </section>
+        <gr-button
+            id="generateButton"
+            on-tap="_handleGenerateTap">Generate new password</gr-button>
+      </div>
+      <span hidden$="[[!_passwordUrl]]">
+        <a href="[[_passwordUrl]]" target="_blank" rel="noopener">
+          Obtain password</a>
+        (opens in a new tab)
+      </span>
     </div>
     <gr-overlay
         id="generatedPasswordOverlay"
diff --git a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.js b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.js
index bde36aa..f4894e9 100644
--- a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.js
+++ b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.js
@@ -20,12 +20,21 @@
     properties: {
       _username: String,
       _generatedPassword: String,
+      _passwordUrl: String,
     },
 
     loadData: function() {
-      return this.$.restAPI.getAccount().then(function(account) {
+      var promises = [];
+
+      promises.push(this.$.restAPI.getAccount().then(function(account) {
         this._username = account.username;
-      }.bind(this));
+      }.bind(this)));
+
+      promises.push(this.$.restAPI.getConfig().then(function(info) {
+        this._passwordUrl = info.auth.http_password_url || null;
+      }.bind(this)));
+
+      return Promise.all(promises);
     },
 
     _handleGenerateTap: function() {
diff --git a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_test.html b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_test.html
index dcda26c..6a162a7 100644
--- a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_test.html
@@ -35,13 +35,16 @@
     var element;
     var account;
     var password;
+    var config;
 
     setup(function(done) {
       account = {username: 'user name'};
+      config = {auth: {}};
       password = 'the password';
 
       stub('gr-rest-api-interface', {
         getAccount: function() { return Promise.resolve(account); },
+        getConfig: function() { return Promise.resolve(config); },
       });
 
       element = fixture('basic');
@@ -72,6 +75,19 @@
         assert.equal(element._generatedPassword, nextPassword);
       });
     });
+
+    test('without http_password_url', function() {
+      assert.isNull(element._passwordUrl);
+    });
+
+    test('with http_password_url', function(done) {
+      config.auth.http_password_url = 'http://example.com/';
+      element.loadData().then(function() {
+        assert.isNotNull(element._passwordUrl);
+        assert.equal(element._passwordUrl, config.auth.http_password_url);
+        done();
+      });
+    });
   });
 
 </script>
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.html b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.html
index 54aafb8..e3aea75 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.html
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.html
@@ -123,14 +123,14 @@
           <gr-button
               on-tap="_handleSaveAccountInfo"
               hidden$="[[!_accountInfoMutable]]"
-              disabled="[[!_accountInfoChanged]]">Save Changes</gr-button>
+              disabled="[[!_accountInfoChanged]]">Save changes</gr-button>
         </fieldset>
         <h2
             id="Preferences"
             class$="[[_computeHeaderClass(_prefsChanged)]]">Preferences</h2>
         <fieldset id="preferences">
           <section>
-            <span class="title">Changes Per Page</span>
+            <span class="title">Changes per page</span>
             <span class="value">
               <select
                   is="gr-select"
@@ -143,7 +143,7 @@
             </span>
           </section>
           <section>
-            <span class="title">Date/Time Format</span>
+            <span class="title">Date/time format</span>
             <span class="value">
               <select
                   is="gr-select"
@@ -163,41 +163,41 @@
             </span>
           </section>
           <section>
-            <span class="title">Email Notifications</span>
+            <span class="title">Email notifications</span>
             <span class="value">
               <select
                   is="gr-select"
                   bind-value="{{_localPrefs.email_strategy}}">
-                <option value="CC_ON_OWN_COMMENTS">Every Comment</option>
-                <option value="ENABLED">Only Comments Left By Others</option>
+                <option value="CC_ON_OWN_COMMENTS">Every comment</option>
+                <option value="ENABLED">Only comments left by others</option>
                 <option value="DISABLED">None</option>
               </select>
             </span>
           </section>
           <section hidden$="[[!_localPrefs.email_format]]">
-            <span class="title">Email Format</span>
+            <span class="title">Email format</span>
             <span class="value">
               <select
                   is="gr-select"
                   bind-value="{{_localPrefs.email_format}}">
-                <option value="HTML_PLAINTEXT">HTML and Plaintext</option>
-                <option value="PLAINTEXT">Plaintext Only</option>
+                <option value="HTML_PLAINTEXT">HTML and plaintext</option>
+                <option value="PLAINTEXT">Plaintext only</option>
               </select>
             </span>
           </section>
           <section>
-            <span class="title">Diff View</span>
+            <span class="title">Diff view</span>
             <span class="value">
               <select
                   is="gr-select"
                   bind-value="{{_localPrefs.diff_view}}">
-                <option value="SIDE_BY_SIDE">Side by Side</option>
-                <option value="UNIFIED_DIFF">Unified Diff</option>
+                <option value="SIDE_BY_SIDE">Side by side</option>
+                <option value="UNIFIED_DIFF">Unified diff</option>
               </select>
             </span>
           </section>
           <section>
-            <span class="title">Expand Inline Diffs</span>
+            <span class="title">Expand inline diffs</span>
             <span class="value">
               <input
                   id="expandInlineDiffs"
@@ -209,7 +209,7 @@
           <gr-button
               id="savePrefs"
               on-tap="_handleSavePreferences"
-              disabled="[[!_prefsChanged]]">Save Changes</gr-button>
+              disabled="[[!_prefsChanged]]">Save changes</gr-button>
         </fieldset>
         <h2
             id="DiffPreferences"
@@ -234,7 +234,7 @@
             </span>
           </section>
           <section>
-            <span class="title">Fit to Screen</span>
+            <span class="title">Fit to screen</span>
             <span class="value">
               <input
                   id="lineWrapping"
@@ -244,7 +244,7 @@
             </span>
           </section>
           <section id="columnsPref" hidden$="[[_diffPrefs.line_wrapping]]">
-            <span class="title">Diff Width</span>
+            <span class="title">Diff width</span>
             <span class="value">
               <input
                   is="iron-input"
@@ -255,7 +255,7 @@
             </span>
           </section>
           <section>
-            <span class="title">Tab Width</span>
+            <span class="title">Tab width</span>
             <span class="value">
               <input
                   is="iron-input"
@@ -266,7 +266,7 @@
             </span>
           </section>
           <section hidden$="[[!_diffPrefs.font_size]]">
-            <span class="title">Font Size</span>
+            <span class="title">Font size</span>
             <span class="value">
               <input
                   is="iron-input"
@@ -277,7 +277,7 @@
             </span>
           </section>
           <section>
-            <span class="title">Show Tabs</span>
+            <span class="title">Show tabs</span>
             <span class="value">
               <input
                   id="showTabs"
@@ -287,7 +287,7 @@
             </span>
           </section>
           <section>
-            <span class="title">Show Trailing Whitespace</span>
+            <span class="title">Show trailing whitespace</span>
             <span class="value">
               <input
                   id="showTrailingWhitespace"
@@ -297,7 +297,7 @@
             </span>
           </section>
           <section>
-            <span class="title">Syntax Highlighting</span>
+            <span class="title">Syntax highlighting</span>
             <span class="value">
               <input
                   id="syntaxHighlighting"
@@ -309,7 +309,7 @@
           <gr-button
               id="saveDiffPrefs"
               on-tap="_handleSaveDiffPreferences"
-              disabled$="[[!_diffPrefsChanged]]">Save Changes</gr-button>
+              disabled$="[[!_diffPrefsChanged]]">Save changes</gr-button>
         </fieldset>
         <h2 id="Menu" class$="[[_computeHeaderClass(_menuChanged)]]">Menu</h2>
         <fieldset id="menu">
@@ -317,7 +317,7 @@
           <gr-button
               id="saveMenu"
               on-tap="_handleSaveMenu"
-              disabled="[[!_menuChanged]]">Save Changes</gr-button>
+              disabled="[[!_menuChanged]]">Save changes</gr-button>
         </fieldset>
         <h2 id="ChangeTableColumns"
             class$="[[_computeHeaderClass(_changeTableChanged)]]">
@@ -330,7 +330,7 @@
           <gr-button
               id="saveChangeTable"
               on-tap="_handleSaveChangeTable"
-              disabled="[[!_changeTableChanged]]">Save Changes</gr-button>
+              disabled="[[!_changeTableChanged]]">Save changes</gr-button>
         </fieldset>
         <h2
             id="Notifications"
@@ -344,7 +344,7 @@
           <gr-button
               on-tap="_handleSaveWatchedProjects"
               disabled$="[[!_watchedProjectsChanged]]"
-              id="_handleSaveWatchedProjects">Save Changes</gr-button>
+              id="_handleSaveWatchedProjects">Save changes</gr-button>
         </fieldset>
         <h2
             id="EmailAddresses"
@@ -357,11 +357,11 @@
               has-unsaved-changes="{{_emailsChanged}}"></gr-email-editor>
           <gr-button
               on-tap="_handleSaveEmails"
-              disabled$="[[!_emailsChanged]]">Save Changes</gr-button>
+              disabled$="[[!_emailsChanged]]">Save changes</gr-button>
         </fieldset>
         <fieldset id="newEmail">
           <section>
-            <span class="title">New Email Address</span>
+            <span class="title">New email address</span>
             <span class="value">
               <input
                   id="newEmailInput"
@@ -383,7 +383,7 @@
           </section>
           <gr-button
               disabled="[[!_computeAddEmailButtonEnabled(_newEmail, _addingEmail)]]"
-              on-tap="_handleAddEmailButton">Send Verification</gr-button>
+              on-tap="_handleAddEmailButton">Send verification</gr-button>
         </fieldset>
         <h2 id="HTTPCredentials">HTTP Credentials</h2>
         <fieldset>
@@ -392,7 +392,7 @@
         <div hidden$="[[!_serverConfig.sshd]]">
           <h2
               id="SSHKeys"
-              class$="[[_computeHeaderClass(_keysChanged)]]">SSH Keys</h2>
+              class$="[[_computeHeaderClass(_keysChanged)]]">SSH keys</h2>
           <gr-ssh-editor
               id="sshEditor"
               has-unsaved-changes="{{_keysChanged}}"></gr-ssh-editor>
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.html b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.html
index 13ca254..b3ce3b4 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.html
@@ -155,30 +155,30 @@
 
     test('user preferences', function(done) {
       // Rendered with the expected preferences selected.
-      assert.equal(valueOf('Changes Per Page', 'preferences')
+      assert.equal(valueOf('Changes per page', 'preferences')
           .firstElementChild.bindValue, preferences.changes_per_page);
-      assert.equal(valueOf('Date/Time Format', 'preferences')
+      assert.equal(valueOf('Date/time format', 'preferences')
           .firstElementChild.bindValue, preferences.date_format);
-      assert.equal(valueOf('Date/Time Format', 'preferences')
+      assert.equal(valueOf('Date/time format', 'preferences')
           .lastElementChild.bindValue, preferences.time_format);
-      assert.equal(valueOf('Email Notifications', 'preferences')
+      assert.equal(valueOf('Email notifications', 'preferences')
           .firstElementChild.bindValue, preferences.email_strategy);
-      assert.equal(valueOf('Email Format', 'preferences')
+      assert.equal(valueOf('Email format', 'preferences')
           .firstElementChild.bindValue, preferences.email_format);
-      assert.equal(valueOf('Diff View', 'preferences')
+      assert.equal(valueOf('Diff view', 'preferences')
           .firstElementChild.bindValue, preferences.diff_view);
-      assert.equal(valueOf('Expand Inline Diffs', 'preferences')
+      assert.equal(valueOf('Expand inline diffs', 'preferences')
           .firstElementChild.checked, false);
 
       assert.isFalse(element._prefsChanged);
       assert.isFalse(element._menuChanged);
 
       // Change the diff view element.
-      var diffSelect = valueOf('Diff View', 'preferences').firstElementChild;
+      var diffSelect = valueOf('Diff view', 'preferences').firstElementChild;
       diffSelect.bindValue = 'SIDE_BY_SIDE';
 
       var expandInlineDiffs =
-          valueOf('Expand Inline Diffs', 'preferences').firstElementChild;
+          valueOf('Expand inline diffs', 'preferences').firstElementChild;
       diffSelect.fire('change');
 
       MockInteractions.tap(expandInlineDiffs);
@@ -207,22 +207,22 @@
       // Rendered with the expected preferences selected.
       assert.equal(valueOf('Context', 'diffPreferences')
           .firstElementChild.bindValue, diffPreferences.context);
-      assert.equal(valueOf('Diff Width', 'diffPreferences')
+      assert.equal(valueOf('Diff width', 'diffPreferences')
           .firstElementChild.bindValue, diffPreferences.line_length);
-      assert.equal(valueOf('Tab Width', 'diffPreferences')
+      assert.equal(valueOf('Tab width', 'diffPreferences')
           .firstElementChild.bindValue, diffPreferences.tab_size);
-      assert.equal(valueOf('Font Size', 'diffPreferences')
+      assert.equal(valueOf('Font size', 'diffPreferences')
           .firstElementChild.bindValue, diffPreferences.font_size);
-      assert.equal(valueOf('Show Tabs', 'diffPreferences')
+      assert.equal(valueOf('Show tabs', 'diffPreferences')
           .firstElementChild.checked, diffPreferences.show_tabs);
-      assert.equal(valueOf('Show Trailing Whitespace', 'diffPreferences')
+      assert.equal(valueOf('Show trailing whitespace', 'diffPreferences')
           .firstElementChild.checked, diffPreferences.show_whitespace_errors);
-      assert.equal(valueOf('Fit to Screen', 'diffPreferences')
+      assert.equal(valueOf('Fit to screen', 'diffPreferences')
           .firstElementChild.checked, diffPreferences.line_wrapping);
 
       assert.isFalse(element._diffPrefsChanged);
 
-      var showTabsCheckbox = valueOf('Show Tabs', 'diffPreferences')
+      var showTabsCheckbox = valueOf('Show tabs', 'diffPreferences')
           .firstElementChild;
       showTabsCheckbox.checked = false;
       element._handleShowTabsChanged();
diff --git a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.html b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.html
index 96d1414..339c7a7 100644
--- a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.html
+++ b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.html
@@ -57,7 +57,7 @@
             <tr>
               <th class="commentHeader">Comment</th>
               <th class="statusHeader">Status</th>
-              <th class="keyHeader">Public Key</th>
+              <th class="keyHeader">Public key</th>
             </tr>
           </thead>
           <tbody>
@@ -87,7 +87,7 @@
               <span class="value">[[_keyToView.algorithm]]</span>
             </section>
             <section>
-              <span class="title">Public Key</span>
+              <span class="title">Public key</span>
               <span class="value publicKey">[[_keyToView.encoded_key]]</span>
             </section>
             <section>
@@ -101,11 +101,11 @@
         </gr-overlay>
         <gr-button
             on-tap="save"
-            disabled$="[[!hasUnsavedChanges]]">Save Changes</gr-button>
+            disabled$="[[!hasUnsavedChanges]]">Save changes</gr-button>
       </fieldset>
       <fieldset>
         <section>
-          <span class="title">New SSH Key</span>
+          <span class="title">New SSH key</span>
           <span class="value">
             <iron-autogrow-textarea
                 id="newKey"
@@ -117,7 +117,7 @@
         <gr-button
             id="addButton"
             disabled$="[[_computeAddButtonDisabled(_newKey)]]"
-            on-tap="_handleAddKey">Add New SSH Key</gr-button>
+            on-tap="_handleAddKey">Add new SSH key</gr-button>
       </fieldset>
     </div>
     <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
diff --git a/polygerrit-ui/app/elements/shared/gr-placeholder/gr-placeholder.html b/polygerrit-ui/app/elements/shared/gr-placeholder/gr-placeholder.html
new file mode 100644
index 0000000..2e624cc
--- /dev/null
+++ b/polygerrit-ui/app/elements/shared/gr-placeholder/gr-placeholder.html
@@ -0,0 +1,53 @@
+<!--
+Copyright (C) 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<link rel="import" href="../../../bower_components/polymer/polymer.html">
+
+<dom-module id="gr-placeholder">
+  <template>
+    <style>
+      main {
+        margin: 2em auto;
+        max-width: 46em;
+      }
+      h1 {
+        margin-bottom: .1em;
+      }
+      @media only screen and (max-width: 67em) {
+        main {
+          margin: 2em 0 2em 15em;
+        }
+      }
+      @media only screen and (max-width: 53em) {
+        .loading {
+          padding: 0 var(--default-horizontal-margin);
+        }
+        main {
+          margin: 2em 1em;
+        }
+      }
+    </style>
+    <main>
+      <h1>[[title]]</h1>
+      <section>
+        This page is not yet implemented in PolyGerrit. View it in the
+        <a id="gwtLink" href$="/?polygerrit=0#[[path]]" rel="external">
+        Old UI</a>
+      </section>
+    </main>
+  </template>
+  <script src="gr-placeholder.js"></script>
+</dom-module>
diff --git a/polygerrit-ui/app/elements/shared/gr-placeholder/gr-placeholder.js b/polygerrit-ui/app/elements/shared/gr-placeholder/gr-placeholder.js
new file mode 100644
index 0000000..0ea2979
--- /dev/null
+++ b/polygerrit-ui/app/elements/shared/gr-placeholder/gr-placeholder.js
@@ -0,0 +1,25 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+(function() {
+  'use strict';
+
+  Polymer({
+    is: 'gr-placeholder',
+
+    properties: {
+      path: String,
+      title: String,
+    },
+  });
+})();
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
index b54840e..7c8df3d 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
@@ -781,6 +781,7 @@
       function onlyParent(c) { return c.side == PARENT_PATCH_NUM; }
       function withoutParent(c) { return c.side != PARENT_PATCH_NUM; }
       function setPath(c) { c.path = opt_path; }
+      function setIsOnParent(c) { c.__isOnParent = true; }
 
       var promises = [];
       var comments;
@@ -800,6 +801,10 @@
         if (opt_basePatchNum == PARENT_PATCH_NUM) {
           baseComments = comments.filter(onlyParent);
           baseComments.forEach(setPath);
+
+          // Translate {String} side to {Boolean} __isOnParent for readability
+          // in the code.
+          baseComments.forEach(setIsOnParent);
         }
         comments = comments.filter(withoutParent);
 
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
index 7a0dc37..8eb2b13 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
@@ -150,6 +150,7 @@
           assert.equal(obj.baseComments.length, 1);
           assert.deepEqual(obj.baseComments[0], {
             side: 'PARENT',
+            __isOnParent: true,
             message: 'how did this work in the first place?',
             path: 'sieve.go',
             updated: '2017-02-03 22:33:28.000000000',