Merge changes Ice480cab,I429e3e10,I4379e493,I592312ed,I69e6d993, ...

* changes:
  CommentDetail: Rewrite switch statement in include method with if + else
  CommentDetail/PatchScriptFactory: Remove unused AccountInfoCache
  EventUtil: Inline AccountJson
  Assignee endpoints: Use AccountLoader to populate AccountInfo
  Anotate GetPastAssignees as singleton
  Assignee endpoints: Use IdentifiedUser#getNameEmail() to format user
diff --git a/polygerrit-ui/app/elements/change/gr-account-entry/gr-account-entry.js b/polygerrit-ui/app/elements/change/gr-account-entry/gr-account-entry.js
index 5dea33d..46f2ed2 100644
--- a/polygerrit-ui/app/elements/change/gr-account-entry/gr-account-entry.js
+++ b/polygerrit-ui/app/elements/change/gr-account-entry/gr-account-entry.js
@@ -69,28 +69,27 @@
     },
 
     _makeSuggestion: function(reviewer) {
+      var name;
+      var value;
+      var generateStatusStr = function(account) {
+        return account.status ? ' (' + account.status + ')' : '';
+      };
       if (reviewer.account) {
         // Reviewer is an account suggestion from getChangeSuggestedReviewers.
-        return {
-          name: reviewer.account.name + ' (' + reviewer.account.email + ')',
-          value: reviewer,
-        };
+        name = reviewer.account.name + ' <' + reviewer.account.email + '>' +
+            generateStatusStr(reviewer.account);
+        value = reviewer;
       } else if (reviewer.group) {
         // Reviewer is a group suggestion from getChangeSuggestedReviewers.
-        return {
-          name: reviewer.group.name + ' (group)',
-          value: reviewer,
-        };
+        name = reviewer.group.name + ' (group)';
+        value = reviewer;
       } else if (reviewer._account_id) {
         // Reviewer is an account suggestion from getSuggestedAccounts.
-        return {
-          name: reviewer.name + ' (' + reviewer.email + ')',
-          value: {
-            account: reviewer,
-            count: 1,
-          },
-        };
+        name = reviewer.name + ' <' + reviewer.email + '>' +
+            generateStatusStr(reviewer);
+        value = {account: reviewer, count: 1};
       }
+      return {name: name, value: value};
     },
 
     _getReviewerSuggestions: function(input) {
@@ -104,7 +103,7 @@
         if (!this.filter) { return reviewers.map(this._makeSuggestion); }
         return reviewers
             .filter(this.filter)
-            .map(this._makeSuggestion);
+            .map(this._makeSuggestion.bind(this));
       }.bind(this));
     },
   });
diff --git a/polygerrit-ui/app/elements/change/gr-account-entry/gr-account-entry_test.html b/polygerrit-ui/app/elements/change/gr-account-entry/gr-account-entry_test.html
index a4635d5..71e84d0 100644
--- a/polygerrit-ui/app/elements/change/gr-account-entry/gr-account-entry_test.html
+++ b/polygerrit-ui/app/elements/change/gr-account-entry/gr-account-entry_test.html
@@ -35,12 +35,13 @@
   suite('gr-account-entry tests', function() {
     var sandbox;
     var _nextAccountId = 0;
-    var makeAccount = function() {
+    var makeAccount = function(opt_status) {
       var accountId = ++_nextAccountId;
       return {
         _account_id: accountId,
         name: 'name ' + accountId,
         email: 'email ' + accountId,
+        status: opt_status,
       };
     };
 
@@ -97,7 +98,7 @@
         var account = makeAccount();
         var suggestion = element._makeSuggestion({account: account});
         assert.deepEqual(suggestion, {
-          name: account.name + ' (' + account.email + ')',
+          name: account.name + ' <' + account.email + '>',
           value: {account: account},
         });
 
@@ -110,7 +111,21 @@
 
         suggestion = element._makeSuggestion(account);
         assert.deepEqual(suggestion, {
-          name: account.name + ' (' + account.email + ')',
+          name: account.name + ' <' + account.email + '>',
+          value: {account: account, count: 1},
+        });
+
+        account = makeAccount('OOO');
+
+        suggestion = element._makeSuggestion({account: account});
+        assert.deepEqual(suggestion, {
+          name: account.name + ' <' + account.email + '> (OOO)',
+          value: {account: account},
+        });
+
+        suggestion = element._makeSuggestion(account);
+        assert.deepEqual(suggestion, {
+          name: account.name + ' <' + account.email + '> (OOO)',
           value: {account: account, count: 1},
         });
       });
diff --git a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.html b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.html
index 14a7260..08e2e21 100644
--- a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.html
+++ b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.html
@@ -62,7 +62,9 @@
                File comment:
              </span>
           </a>
-          <gr-formatted-text class="message"
+          <gr-formatted-text
+              class="message"
+              no-trailing-margin
               content="[[comment.message]]"
               config="[[projectConfig.commentlinks]]"></gr-formatted-text>
         </div>
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 bb9cf15..1ab8a77 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
@@ -189,15 +189,15 @@
       <div>Files</div>
       <div class="rightControls">
         <template is="dom-if"
-            if="[[_fileListActionsVisible(_numFilesShown, _maxFilesForBulkActions)]]">
+            if="[[_fileListActionsVisible(_shownFiles.*, _maxFilesForBulkActions)]]">
           <gr-button link on-tap="_expandAllDiffs">Show diffs</gr-button>
           <span class="separator">/</span>
           <gr-button link on-tap="_collapseAllDiffs">Hide diffs</gr-button>
         </template>
         <template is="dom-if"
-            if="[[!_fileListActionsVisible(_numFilesShown, _maxFilesForBulkActions)]]">
+            if="[[!_fileListActionsVisible(_shownFiles.*, _maxFilesForBulkActions)]]">
           <div class="warning">
-            Bulk file list actions disabled for large amounts of files
+            Bulk actions disabled because there are too many files.
           </div>
         </template>
         <span class="separator">/</span>
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 ec463b6..ca1ffe9 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
@@ -102,7 +102,7 @@
       _maxFilesForBulkActions: {
         type: Number,
         readOnly: true,
-        value: 225,
+        value: 50,
       },
     },
 
@@ -649,8 +649,9 @@
       return 'SIDE_BY_SIDE';
     },
 
-    _fileListActionsVisible: function(numFilesShown, maxFilesForBulkActions) {
-      return numFilesShown <= maxFilesForBulkActions;
+    _fileListActionsVisible: function(shownFilesRecord,
+        maxFilesForBulkActions) {
+      return shownFilesRecord.base.length <= maxFilesForBulkActions;
     },
 
     _computePatchSetDescription: function(revisions, patchNum) {
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
index 28a784d..4c8b4f1 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
@@ -616,15 +616,14 @@
     });
 
     test('show/hide diffs disabled for large amounts of files', function(done) {
+      var computeSpy = sandbox.spy(element, '_fileListActionsVisible');
       element._files = [];
       element.changeNum = '42';
       element.patchRange = {
         basePatchNum: 'PARENT',
         patchNum: '2',
       };
-      var computeSpy = sandbox.spy(element, '_fileListActionsVisible');
       element.$.fileCursor.setCursorAtIndex(0);
-      element._numFilesShown = 1;
       flush(function() {
         assert.isTrue(computeSpy.lastCall.returnValue);
         var arr = [];
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 e58f1f2..d96237e 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
@@ -15,7 +15,9 @@
 -->
 
 <link rel="import" href="../../../bower_components/polymer/polymer.html">
+<link rel="import" href="../../../styles/gr-settings-styles.html">
 <link rel="import" href="../../shared/gr-button/gr-button.html">
+<link rel="import" href="../../shared/gr-overlay/gr-overlay.html">
 <link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
 
 <dom-module id="gr-http-password">
@@ -24,9 +26,24 @@
       .password {
         font-family: var(--monospace-font-family);
       }
-      .noPassword {
-        color: #777;
+      #generatedPasswordOverlay {
+        padding: 2em;
+        width: 50em;
+      }
+      #generatedPasswordDisplay {
+        margin: 1em 0;
+      }
+      #generatedPasswordDisplay .value {
+        font-family: var(--monospace-font-family);
+      }
+      #passwordWarning {
         font-style: italic;
+        text-align: center;
+      }
+      .closeButton {
+        bottom: 2em;
+        position: absolute;
+        right: 2em;
       }
     </style>
     <style include="gr-settings-styles"></style>
@@ -35,28 +52,28 @@
         <span class="title">Username</span>
         <span class="value">[[_username]]</span>
       </section>
-      <section>
-        <span class="title">Password</span>
-        <span hidden$="[[!_hasPassword]]">
-          <span class="value" hidden$="[[_passwordVisible]]">
-            <gr-button
-                link
-                on-tap="_handleViewPasswordTap">Click to view</gr-button>
-          </span>
-          <span
-              class="value password"
-              hidden$="[[!_passwordVisible]]">[[_password]]</span>
-        </span>
-        <span class="value noPassword" hidden$="[[_hasPassword]]">(None)</span>
-      </section>
       <gr-button
           id="generateButton"
           on-tap="_handleGenerateTap">Generate New Password</gr-button>
-      <gr-button
-          id="clearButton"
-          on-tap="_handleClearTap"
-          disabled="[[!_hasPassword]]">Clear Password</gr-button>
     </div>
+    <gr-overlay
+        id="generatedPasswordOverlay"
+        on-iron-overlay-closed="_generatedPasswordOverlayClosed"
+        with-backdrop>
+      <div class="gr-settings-styles">
+        <section id="generatedPasswordDisplay">
+          <span class="title">New Password:</span>
+          <span class="value">[[_generatedPassword]]</span>
+        </section>
+        <section id="passwordWarning">
+          This password will not be displayed again.<br>
+          If you lose it, you will need to generate a new one.
+        </section>
+        <gr-button
+            class="closeButton"
+            on-tap="_closeOverlay">Close</gr-button>
+      </div>
+    </gr-overlay>
     <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
   </template>
   <script src="gr-http-password.js"></script>
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 9248632..bde36aa 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
@@ -17,65 +17,31 @@
   Polymer({
     is: 'gr-http-password',
 
-    /**
-     * Fired when getting the password fails with non-404.
-     *
-     * @event network-error
-     */
-
     properties: {
-      _serverConfig: Object,
       _username: String,
-      _password: String,
-      _passwordVisible: {
-        type: Boolean,
-        value: false,
-      },
-      _hasPassword: Boolean,
+      _generatedPassword: String,
     },
 
     loadData: function() {
-      var promises = [];
-
-      promises.push(this.$.restAPI.getAccount().then(function(account) {
+      return this.$.restAPI.getAccount().then(function(account) {
         this._username = account.username;
-      }.bind(this)));
-
-      promises.push(this.$.restAPI
-          .getAccountHttpPassword(this._handleGetPasswordError.bind(this))
-          .then(function(pass) {
-            this._password = pass;
-            this._hasPassword = !!pass;
-          }.bind(this)));
-
-      return Promise.all(promises);
-    },
-
-    _handleGetPasswordError: function(response) {
-      if (response.status === 404) {
-        this._hasPassword = false;
-      } else {
-        this.fire('network-error', {response: response});
-      }
-    },
-
-    _handleViewPasswordTap: function() {
-      this._passwordVisible = true;
+      }.bind(this));
     },
 
     _handleGenerateTap: function() {
+      this._generatedPassword = 'Generating...';
+      this.$.generatedPasswordOverlay.open();
       this.$.restAPI.generateAccountHttpPassword().then(function(newPassword) {
-        this._hasPassword = true;
-        this._passwordVisible = true;
-        this._password = newPassword;
+        this._generatedPassword = newPassword;
       }.bind(this));
     },
 
-    _handleClearTap: function() {
-      this.$.restAPI.deleteAccountHttpPassword().then(function() {
-        this._password = '';
-        this._hasPassword = false;
-      }.bind(this));
+    _closeOverlay: function() {
+      this.$.generatedPasswordOverlay.close();
+    },
+
+    _generatedPasswordOverlayClosed: function() {
+      this._generatedPassword = null;
     },
   });
 })();
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 36c9abf..e675de2 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
@@ -31,7 +31,7 @@
 </test-fixture>
 
 <script>
-  suite('gr-http-password tests (already has password)', function() {
+  suite('gr-http-password tests', function() {
     var element;
     var account;
     var password;
@@ -51,106 +51,30 @@
       element.loadData().then(function() { flush(done); });
     });
 
-    test('loads data', function() {
-      assert.equal(element._username, 'user name');
-      assert.equal(element._password, 'the password');
-      assert.isFalse(element._passwordVisible);
-      assert.isTrue(element._hasPassword);
-    });
-
-    test('view password', function() {
-      var button = element.$$('.value gr-button');
-      assert.isFalse(element._passwordVisible);
-      MockInteractions.tap(button);
-      assert.isTrue(element._passwordVisible);
-    });
-
     test('generate password', function() {
       var button = element.$.generateButton;
       var nextPassword = 'the new password';
+      var generateResolve;
       var generateStub = sinon.stub(element.$.restAPI,
           'generateAccountHttpPassword', function() {
-            return Promise.resolve(nextPassword);
+            return new Promise(function(resolve) {
+              generateResolve = resolve;
+            });
           });
 
-      assert.isTrue(element._hasPassword);
-      assert.isFalse(element._passwordVisible);
-      assert.equal(element._password, 'the password');
+      assert.isNotOk(element._generatedPassword);
 
       MockInteractions.tap(button);
 
       assert.isTrue(generateStub.called);
+      assert.equal(element._generatedPassword, 'Generating...');
+
+      generateResolve(nextPassword);
+
       generateStub.lastCall.returnValue.then(function() {
-        assert.isTrue(element._passwordVisible);
-        assert.isTrue(element._hasPassword);
-        assert.equal(element._password, 'the new password');
-      });
-    });
-
-    test('clear password', function() {
-      var button = element.$.clearButton;
-      var clearStub = sinon.stub(element.$.restAPI, 'deleteAccountHttpPassword',
-          function() { return Promise.resolve(); });
-
-      assert.isTrue(element._hasPassword);
-      assert.equal(element._password, 'the password');
-
-      MockInteractions.tap(button);
-
-      assert.isTrue(clearStub.called);
-      clearStub.lastCall.returnValue.then(function() {
-        assert.isFalse(element._hasPassword);
-        assert.equal(element._password, '');
+        assert.equal(element._generatedPassword, nextPassword);
       });
     });
   });
 
-  suite('gr-http-password tests (has no password)', function() {
-    var element;
-    var account;
-
-    setup(function(done) {
-      account = {username: 'user name'};
-
-      stub('gr-rest-api-interface', {
-        getAccount: function() { return Promise.resolve(account); },
-        getAccountHttpPassword: function(errFn) {
-          errFn({status: 404});
-          return Promise.resolve('');
-        },
-      });
-
-      element = fixture('basic');
-      element.loadData().then(function() { flush(done); });
-    });
-
-    test('loads data', function() {
-      assert.equal(element._username, 'user name');
-      assert.isNotOk(element._password);
-      assert.isFalse(element._passwordVisible);
-      assert.isFalse(element._hasPassword);
-    });
-
-    test('generate password', function() {
-      var button = element.$.generateButton;
-      var nextPassword = 'the new password';
-      var generateStub = sinon.stub(element.$.restAPI,
-          'generateAccountHttpPassword', function() {
-            return Promise.resolve(nextPassword);
-          });
-
-      assert.isFalse(element._hasPassword);
-      assert.isFalse(element._passwordVisible);
-      assert.isNotOk(element._password);
-
-      MockInteractions.tap(button);
-
-      assert.isTrue(generateStub.called);
-      generateStub.lastCall.returnValue.then(function() {
-        assert.isTrue(element._passwordVisible);
-        assert.isOk(element._hasPassword);
-        assert.equal(element._password, 'the new password');
-      });
-    });
-  });
 </script>
diff --git a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.html b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.html
index 1d2beab..43721fe 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.html
+++ b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.html
@@ -44,6 +44,9 @@
         <span hidden$="[[!_computeShowEmail(showEmail, account)]]">
           [[_computeEmailStr(account)]]
         </span>
+        <template is="dom-if" if="[[account.status]]">
+          <span>([[account.status]])</span>
+        </template>
       </span>
     </span>
   </template>
diff --git a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.html b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.html
index 11560f1..8855b0a 100644
--- a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.html
+++ b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.html
@@ -29,6 +29,12 @@
       gr-linked-text.pre {
         margin: 0 0 1.4em 0;
       }
+      :host.noTrailingMargin p:last-child,
+      :host.noTrailingMargin ul:last-child,
+      :host.noTrailingMargin blockquote:last-child,
+      :host.noTrailingMargin gr-linked-text.pre:last-child {
+        margin: 0;
+      }
       blockquote {
         border-left: 1px solid #aaa;
         padding: 0 .7em;
diff --git a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.js b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.js
index 1b129a7..c17e9e4 100644
--- a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.js
+++ b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.js
@@ -22,12 +22,22 @@
     properties: {
       content: String,
       config: Object,
+      noTrailingMargin: {
+        type: Boolean,
+        value: false,
+      },
     },
 
     observers: [
       '_contentOrConfigChanged(content, config)',
     ],
 
+    ready: function() {
+      if (this.noTrailingMargin) {
+        this.classList.add('noTrailingMargin');
+      }
+    },
+
     /**
      * Get the plain text as it appears in the generated DOM.
      *