Merge "ReceiveCommits: Retry change queries to find changes for pushed commits"
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 4d2fd35..6b3b79f 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -2595,6 +2595,18 @@
 link:access-control.html#capability_queryLimit[queryLimit]
 which is defaulted to 500 entries.
 
+[[gerrit.projectStatePredicateEnabled]]
++
+Indicates whether the link:rest-api-projects.html[/projects/] REST API endpoint
+supports filtering projects by state. The value is exposed in
+link:rest-api-config.html[/config/server/info] REST API endpoint.
++
+Instances having a custom implementation of ProjectQueryBuilder might have
+disabled the `state` predicate in which case the setting should be set to
+`false`.
++
+Default: `true`.
+
 [[gerrit.primaryWeblinkName]]gerrit.primaryWeblinkName::
 +
 Name of the link:dev-plugins.html#links-to-external-tools[Weblink] that should
diff --git a/Documentation/rest-api-config.txt b/Documentation/rest-api-config.txt
index a963edb..b893245 100644
--- a/Documentation/rest-api-config.txt
+++ b/Documentation/rest-api-config.txt
@@ -152,7 +152,8 @@
     "gerrit": {
       "all_projects": "All-Projects",
       "all_users": "All-Users"
-      "doc_search": true
+      "doc_search": true,
+      "project_state_predicate_enabled": true
     },
     "sshd": {},
     "suggest": {
@@ -2296,6 +2297,8 @@
 Gerrit base path even if this value is unset.)
 |`edit_gpg_keys`     |not set if `false`|
 Whether to enable the web UI for editing GPG keys.
+|`project_state_predicate_enabled` ||
+link:config-gerrit.html#gerrit.projectStatePredicateEnabled[Whether the instance supports filtering projects by state].
 |`report_bug_url`    |optional|
 link:config-gerrit.html#gerrit.reportBugUrl[URL to report bugs].
 |`instance_id`       |optional|
diff --git a/java/com/google/gerrit/extensions/common/GerritInfo.java b/java/com/google/gerrit/extensions/common/GerritInfo.java
index 547e606..fd682c1 100644
--- a/java/com/google/gerrit/extensions/common/GerritInfo.java
+++ b/java/com/google/gerrit/extensions/common/GerritInfo.java
@@ -25,4 +25,5 @@
   public String primaryWeblinkName;
   public String instanceId;
   public String defaultBranch;
+  public Boolean projectStatePredicateEnabled;
 }
diff --git a/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java b/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java
index 6b19906..02ae629 100644
--- a/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java
+++ b/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java
@@ -260,7 +260,8 @@
         maxSize,
         expireAfterWrite,
         refreshAfterWrite,
-        buildBloomFilter);
+        buildBloomFilter,
+        isOfflineReindex);
   }
 
   private boolean has(String name, String var) {
diff --git a/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java b/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java
index c31f58a..de61a16 100644
--- a/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java
+++ b/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java
@@ -359,6 +359,7 @@
     private volatile BloomFilter<K> bloomFilter;
     private int estimatedSize;
     private boolean buildBloomFilter;
+    private boolean isOfflineReindex;
 
     SqlStore(
         String jdbcUrl,
@@ -369,7 +370,8 @@
         long maxSize,
         @Nullable Duration expireAfterWrite,
         @Nullable Duration refreshAfterWrite,
-        boolean buildBloomFilter) {
+        boolean buildBloomFilter,
+        boolean isOfflineReindex) {
       this.url = jdbcUrl;
       this.keyType = createKeyType(keyType, keySerializer);
       this.valueSerializer = valueSerializer;
@@ -378,6 +380,7 @@
       this.expireAfterWrite = expireAfterWrite;
       this.refreshAfterWrite = refreshAfterWrite;
       this.buildBloomFilter = buildBloomFilter;
+      this.isOfflineReindex = isOfflineReindex;
 
       int cores = Runtime.getRuntime().availableProcessors();
       int keep = Math.min(cores, 16);
@@ -501,7 +504,9 @@
           ValueHolder<V> h = new ValueHolder<>(val, created.toInstant());
           h.clean = true;
           hitCount.incrementAndGet();
-          touch(c, key);
+          if (!isOfflineReindex) {
+            touch(c, key);
+          }
           return h;
         } finally {
           c.get.clearParameters();
diff --git a/java/com/google/gerrit/server/query/project/ProjectQueryBuilder.java b/java/com/google/gerrit/server/query/project/ProjectQueryBuilder.java
index ade6606..c70f00f 100644
--- a/java/com/google/gerrit/server/query/project/ProjectQueryBuilder.java
+++ b/java/com/google/gerrit/server/query/project/ProjectQueryBuilder.java
@@ -23,6 +23,8 @@
  * Provides methods required for parsing projects queries.
  *
  * <p>Internally (at google), this interface has a different implementation, comparing to upstream.
+ * For example, Google disables the `state` predicate which can expose it by setting
+ * `gerrit.projectStatePredicateEnabled = false`.
  */
 public interface ProjectQueryBuilder {
   String FIELD_LIMIT = "limit";
diff --git a/java/com/google/gerrit/server/restapi/config/GetServerInfo.java b/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
index a9f16e7..91d24b9 100644
--- a/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
+++ b/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
@@ -296,6 +296,8 @@
     info.primaryWeblinkName = config.getString("gerrit", null, "primaryWeblinkName");
     info.instanceId = instanceId;
     info.defaultBranch = config.getString("gerrit", null, "defaultBranch");
+    info.projectStatePredicateEnabled =
+        config.getBoolean("gerrit", null, "projectStatePredicateEnabled", true);
     return info;
   }
 
diff --git a/javatests/com/google/gerrit/server/cache/h2/H2CacheTest.java b/javatests/com/google/gerrit/server/cache/h2/H2CacheTest.java
index 8c4eb08..b7f566db 100644
--- a/javatests/com/google/gerrit/server/cache/h2/H2CacheTest.java
+++ b/javatests/com/google/gerrit/server/cache/h2/H2CacheTest.java
@@ -72,7 +72,8 @@
         1 << 20,
         expireAfterWrite,
         refreshAfterWrite,
-        true);
+        true,
+        false);
   }
 
   @Test
diff --git a/modules/jgit b/modules/jgit
index 76ce6d9..cfdfb01 160000
--- a/modules/jgit
+++ b/modules/jgit
@@ -1 +1 @@
-Subproject commit 76ce6d91a2e07fdfcbfc8df6970c9e98a98e36a0
+Subproject commit cfdfb01f4c7de1d61a4913deac1d02837b53df82
diff --git a/plugins/replication b/plugins/replication
index 05c096e..3982574 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit 05c096ed827467645776abcec6b39523b4e76843
+Subproject commit 3982574d28f254b525b093c2ecae8caa47825910
diff --git a/polygerrit-ui/app/api/diff.ts b/polygerrit-ui/app/api/diff.ts
index aa7aa30..90cf17b 100644
--- a/polygerrit-ui/app/api/diff.ts
+++ b/polygerrit-ui/app/api/diff.ts
@@ -401,10 +401,6 @@
       value: boolean;
       source: 'controls' | 'magnifier';
     }
-  | {
-      type: 'ignore-option-changed';
-      ignoreOption: resemble.ComparisonIgnoreOption;
-    }
   | {type: 'zoom-level-changed'; scale: number | 'fit'}
   | {type: 'follow-mouse-changed'; value: boolean}
   | {type: 'background-color-changed'; value: string}
@@ -556,3 +552,13 @@
     intentionalMove?: boolean
   ): void;
 }
+
+/**
+ * Represents a list of ranges in a diff that should be focused.
+ *
+ * This is used to collapse diff chunks that are not in focus.
+ */
+export declare interface DiffRangesToFocus {
+  left: {start: number; end: number}[];
+  right: {start: number; end: number}[];
+}
diff --git a/polygerrit-ui/app/api/rest-api.ts b/polygerrit-ui/app/api/rest-api.ts
index c354d2e..a99771b 100644
--- a/polygerrit-ui/app/api/rest-api.ts
+++ b/polygerrit-ui/app/api/rest-api.ts
@@ -708,6 +708,7 @@
   doc_search: boolean;
   doc_url?: string;
   edit_gpg_keys?: boolean;
+  project_state_predicate_enabled: boolean;
   report_bug_url?: string;
   // The following property is missed in doc
   primary_weblink_name?: string;
diff --git a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts
index 704cecf..7b2d3b0 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts
@@ -217,7 +217,8 @@
       // account.
       isDetailedAccount(account) &&
       account !== this.account &&
-      account._account_id === this.account._account_id
+      (!this.account._account_id ||
+        account._account_id === this.account._account_id)
     ) {
       // AccountInfo returned by fillDetails has the email property set
       // to the primary email of the account. This poses a problem in
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-builder/token-highlight-layer.ts b/polygerrit-ui/app/embed/diff/gr-diff-builder/token-highlight-layer.ts
index a9e332a..e1728ff 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-builder/token-highlight-layer.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-builder/token-highlight-layer.ts
@@ -233,6 +233,10 @@
     // it's a shadow dom.
     const {element} = this.findTokenAncestor(e.composedPath()[0]);
     if (element) return;
+    this.removeHighlight();
+  }
+
+  private removeHighlight() {
     this.hoveredElement = undefined;
     this.updateTokenTask?.cancel();
     this.updateTokenHighlight(undefined, 0, undefined);
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/gr-image-viewer.ts b/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/gr-image-viewer.ts
index 44cef43..e0febdc 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/gr-image-viewer.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/gr-image-viewer.ts
@@ -35,15 +35,6 @@
 
 const AUTOMATIC_BLINK_BUTTON_ACTIVE_AREA_PIXELS = 350;
 
-const IGNORE_OPTION_DESCRIPTIONS = {
-  // resemble.ComparisonIgnoreOption: string
-  nothing: 'All differences',
-  less: 'Only substantial differences',
-  colors: 'Ignore colors changes',
-  alpha: 'Ignore alpha channel changes',
-  antialiasing: 'Ignore anti-aliasing changes',
-};
-
 /**
  * This components allows the user to rapidly switch between two given images
  * rendered in the same location, to make subtle differences more noticeable.
@@ -63,9 +54,6 @@
    */
   @property({type: Boolean}) automaticBlink = false;
 
-  @property({type: String})
-  ignoreOption: resemble.ComparisonIgnoreOption = 'less';
-
   @state() protected baseSelected = false;
 
   @state() protected scaledSelected = true;
@@ -312,12 +300,6 @@
         #highlight-changes {
           margin: var(--spacing-m) var(--spacing-xl);
         }
-        #ignore-option-intro {
-          margin: 0 var(--spacing-xl);
-        }
-        .ignoreOption {
-          margin: 0 var(--spacing-xxl);
-        }
         gr-overview-image {
           min-width: 200px;
           min-height: 150px;
@@ -509,31 +491,6 @@
         `
       : '';
 
-    let ignoreOptionRadioGroup;
-    if (this.diffHighlightSrc && this.showHighlight) {
-      for (const [ignoreOption, description] of Object.entries(
-        IGNORE_OPTION_DESCRIPTIONS
-      ) as [resemble.ComparisonIgnoreOption, String][]) {
-        const id = `ignore-${String(ignoreOption)}`;
-        ignoreOptionRadioGroup = html`
-          ${ignoreOptionRadioGroup}
-          <div id=${id} class="ignoreOption">
-            <input
-              id="${id}-input"
-              type="radio"
-              name="ignoreOption"
-              ?checked=${ignoreOption === this.ignoreOption}
-              ?disabled=${!this.showHighlight}
-              @click=${() => {
-                this.selectIgnoreOption(ignoreOption);
-              }}
-            />
-            <label id="${id}-label" for="${id}-input">${description}</label>
-          </div>
-        `;
-      }
-    }
-
     const overviewImage = html`
       <gr-overview-image
         .frameRect=${this.overviewFrame}
@@ -681,8 +638,7 @@
       </div>
 
       <paper-card class="controls">
-        ${versionSwitcher} ${highlightSwitcher} ${ignoreOptionRadioGroup}
-        ${overviewImage} ${zoomControl}
+        ${versionSwitcher} ${highlightSwitcher} ${overviewImage} ${zoomControl}
         ${!this.scaledSelected ? followMouse : ''} ${backgroundPicker}
       </paper-card>
     `;
@@ -719,9 +675,7 @@
     }
     if (
       this.canHighlightDiffs &&
-      (changedProperties.has('baseUrl') ||
-        changedProperties.has('revisionUrl') ||
-        changedProperties.has('ignoreOption'))
+      (changedProperties.has('baseUrl') || changedProperties.has('revisionUrl'))
     ) {
       this.computeDiffImage();
     }
@@ -729,17 +683,17 @@
 
   private computeDiffImage() {
     if (!(this.baseUrl && this.revisionUrl)) return;
-
-    window.resemble.compare(
-      this.baseUrl,
-      this.revisionUrl,
-      {
-        ignore: this.ignoreOption,
-      },
-      (_err, data) => {
-        this.diffHighlightSrc = data.getImageDataUrl();
-      }
-    );
+    window
+      .resemble(this.baseUrl)
+      .compareTo(this.revisionUrl)
+      // By default Resemble.js applies some color / alpha tolerance as well as
+      // min / max brightness beyond which to ignore changes. Until we have
+      // controls to let the user affect these options, always highlight all
+      // changed pixels.
+      .ignoreNothing()
+      .onComplete(result => {
+        this.diffHighlightSrc = result.getImageDataUrl();
+      });
   }
 
   fireAction(detail: ImageDiffAction) {
@@ -813,14 +767,6 @@
     });
   }
 
-  selectIgnoreOption(ignoreOption: resemble.ComparisonIgnoreOption) {
-    this.ignoreOption = ignoreOption;
-    this.fireAction({
-      type: 'ignore-option-changed',
-      ignoreOption: this.ignoreOption,
-    });
-  }
-
   zoomControlChanged(event: ValueChangedEvent<string>) {
     const scaleString = event.detail.value;
     if (!scaleString) return;
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-model/gr-diff-model.ts b/polygerrit-ui/app/embed/diff/gr-diff-model/gr-diff-model.ts
index 88451f6..8488bd5 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-model/gr-diff-model.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-model/gr-diff-model.ts
@@ -10,6 +10,7 @@
   DiffInfo,
   DiffLayer,
   DiffPreferencesInfo,
+  DiffRangesToFocus,
   DiffResponsiveMode,
   DiffViewMode,
   DisplayLine,
@@ -51,6 +52,7 @@
   renderPrefs: RenderPreferences;
   diffPrefs: DiffPreferencesInfo;
   lineOfInterest?: DisplayLine;
+  diffRangesToFocus?: DiffRangesToFocus;
   comments: GrDiffCommentThread[];
   groups: GrDiffGroup[];
   /** how much context to show for large files */
@@ -211,6 +213,9 @@
       computeKeyLocations(diffState.lineOfInterest, diffState.comments ?? [])
   );
 
+  readonly diffRangesToFocus$: Observable<DiffRangesToFocus | undefined> =
+    select(this.state$, diffState => diffState.diffRangesToFocus);
+
   constructor(
     /**
      * Normally a reference to the <gr-diff> component. Used for firing events
@@ -232,23 +237,31 @@
   }
 
   processDiff() {
-    return combineLatest([this.diff$, this.context$, this.renderPrefs$])
+    return combineLatest([
+      this.diff$,
+      this.context$,
+      this.renderPrefs$,
+      this.diffRangesToFocus$,
+    ])
       .pipe(
         withLatestFrom(this.keyLocations$),
         debounceTime(1),
-        map(([[diff, context, renderPrefs], keyLocations]) => {
-          const options: ProcessingOptions = {
-            context,
-            keyLocations,
-            isBinary: !!(isImageDiff(diff) || diff.binary),
-          };
-          if (renderPrefs?.num_lines_rendered_at_once) {
-            options.asyncThreshold = renderPrefs.num_lines_rendered_at_once;
-          }
+        map(
+          ([[diff, context, renderPrefs, diffRangesToFocus], keyLocations]) => {
+            const options: ProcessingOptions = {
+              context,
+              keyLocations,
+              isBinary: !!(isImageDiff(diff) || diff.binary),
+              diffRangesToFocus,
+            };
+            if (renderPrefs?.num_lines_rendered_at_once) {
+              options.asyncThreshold = renderPrefs.num_lines_rendered_at_once;
+            }
 
-          const processor = new GrDiffProcessor(options);
-          return processor.process(diff.content);
-        })
+            const processor = new GrDiffProcessor(options);
+            return processor.process(diff.content);
+          }
+        )
       )
       .subscribe(groups => {
         this.updateState({groups});
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-processor/gr-diff-processor.ts b/polygerrit-ui/app/embed/diff/gr-diff-processor/gr-diff-processor.ts
index 6b7b45f..1561dad 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-processor/gr-diff-processor.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-processor/gr-diff-processor.ts
@@ -9,7 +9,7 @@
   GrDiffGroupType,
   hideInContextControl,
 } from '../gr-diff/gr-diff-group';
-import {DiffContent} from '../../../types/diff';
+import {DiffContent, DiffRangesToFocus} from '../../../types/diff';
 import {Side} from '../../../constants/constants';
 import {getStringLength} from '../gr-diff-highlight/gr-annotation';
 import {GrDiffLineType, LineNumber} from '../../../api/diff';
@@ -41,6 +41,7 @@
   keyLocations?: KeyLocations;
   asyncThreshold?: number;
   isBinary?: boolean;
+  diffRangesToFocus?: DiffRangesToFocus;
 }
 
 /**
diff --git a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-styles.ts b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-styles.ts
index 1de8298..22a7694 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-styles.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-styles.ts
@@ -670,9 +670,17 @@
 
 // Styles related to the <gr-diff-text> component.
 export const grDiffTextStyles = css`
-  gr-diff-text .token-highlight {
+  /* The background color for tokens of the "token-highlight-layer". */
+  gr-diff-text hl.token-highlight {
     background-color: var(--token-highlighting-color, #fffd54);
   }
+  /* We do not want token highlighting to override the "rangeHighlight"
+    color, so let's make sure that there are no "rangeHighlight" element
+    parents that wrap the "token-highlight" element.
+  */
+  gr-diff-text hl.rangeHighlight hl.token-highlight {
+    background-color: transparent;
+  }
   /* Describes two states of semantic tokens: whenever a token has a
      definition that can be navigated to (navigable) and whenever
      the token is actually clickable to perform this navigation. */
diff --git a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts
index 90b9cfe..f3534c2 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts
@@ -44,6 +44,7 @@
   RenderPreferences,
   GrDiff as GrDiffApi,
   DisplayLine,
+  DiffRangesToFocus,
   LineNumber,
   ContentLoadNeededEventDetail,
   DiffContextExpandedExternalDetail,
@@ -182,6 +183,9 @@
   @property({type: Object})
   lineOfInterest?: DisplayLine;
 
+  @property({type: Object})
+  diffRangesToFocus?: DiffRangesToFocus;
+
   /**
    * True when diff is changed, until the content is done rendering.
    * Use getter/setter loading instead of this.
@@ -368,7 +372,8 @@
       changedProperties.has('showNewlineWarningLeft') ||
       changedProperties.has('showNewlineWarningRight') ||
       changedProperties.has('prefs') ||
-      changedProperties.has('lineOfInterest')
+      changedProperties.has('lineOfInterest') ||
+      changedProperties.has('diffRangesToFocus')
     ) {
       if (this.diff && this.prefs) {
         const renderPrefs = {...(this.renderPrefs ?? {})};
@@ -394,6 +399,7 @@
           renderPrefs,
           diffPrefs: this.prefs,
           lineOfInterest: this.lineOfInterest,
+          diffRangesToFocus: this.diffRangesToFocus,
         });
       }
     }
diff --git a/polygerrit-ui/app/embed/diff/gr-ranged-comment-themes/gr-ranged-comment-theme.ts b/polygerrit-ui/app/embed/diff/gr-ranged-comment-themes/gr-ranged-comment-theme.ts
index 38a9533..c67157f 100644
--- a/polygerrit-ui/app/embed/diff/gr-ranged-comment-themes/gr-ranged-comment-theme.ts
+++ b/polygerrit-ui/app/embed/diff/gr-ranged-comment-themes/gr-ranged-comment-theme.ts
@@ -8,10 +8,10 @@
 const $_documentContainer = document.createElement('template');
 
 export const grRangedCommentTheme = css`
-  .rangeHighlight {
+  gr-diff-text hl.rangeHighlight {
     background-color: var(--diff-highlight-range-color);
   }
-  .rangeHoverHighlight {
+  gr-diff-text hl.rangeHoverHighlight {
     background-color: var(--diff-highlight-range-hover-color);
   }
 `;
diff --git a/polygerrit-ui/app/styles/themes/app-theme.ts b/polygerrit-ui/app/styles/themes/app-theme.ts
index 7742b1f..a85b5d0 100644
--- a/polygerrit-ui/app/styles/themes/app-theme.ts
+++ b/polygerrit-ui/app/styles/themes/app-theme.ts
@@ -417,8 +417,8 @@
     --diff-context-control-background-color: #fff7d4;
     --diff-context-control-border-color: #f6e6a5;
     --diff-context-control-color: var(--default-button-text-color);
-    --diff-highlight-range-color: rgba(255, 213, 0, 0.5);
-    --diff-highlight-range-hover-color: rgba(255, 255, 0, 0.5);
+    --diff-highlight-range-color: rgba(255, 220, 0, 0.5);
+    --diff-highlight-range-hover-color: rgba(255, 190, 0, 0.5);
     --diff-selection-background-color: #c7dbf9;
     --diff-tab-indicator-color: var(--deemphasized-text-color);
     --diff-trailing-whitespace-indicator: #ff9ad2;
diff --git a/polygerrit-ui/app/test/test-data-generators.ts b/polygerrit-ui/app/test/test-data-generators.ts
index 7d666e8..22dbe7c1 100644
--- a/polygerrit-ui/app/test/test-data-generators.ts
+++ b/polygerrit-ui/app/test/test-data-generators.ts
@@ -490,6 +490,7 @@
     all_projects: 'All-Projects',
     all_users: 'All-Users',
     doc_search: false,
+    project_state_predicate_enabled: true,
   };
 }
 
diff --git a/polygerrit-ui/app/types/diff.ts b/polygerrit-ui/app/types/diff.ts
index 2a8c7e5..0d1592e 100644
--- a/polygerrit-ui/app/types/diff.ts
+++ b/polygerrit-ui/app/types/diff.ts
@@ -16,6 +16,7 @@
   DiffFileMetaInfo as DiffFileMetaInfoApi,
   DiffInfo as DiffInfoApi,
   DiffIntralineInfo,
+  DiffRangesToFocus,
   DiffResponsiveMode,
   DiffPreferencesInfo as DiffPreferenceInfoApi,
   IgnoreWhitespaceType,
@@ -27,6 +28,7 @@
 export type {
   ChangeType,
   DiffIntralineInfo,
+  DiffRangesToFocus,
   DiffResponsiveMode,
   IgnoreWhitespaceType,
   MarkLength,
diff --git a/tools/nongoogle.bzl b/tools/nongoogle.bzl
index 91caf31..d9b90d8 100644
--- a/tools/nongoogle.bzl
+++ b/tools/nongoogle.bzl
@@ -137,18 +137,18 @@
         sha1 = "cb2f351bf4463751201f43bb99865235d5ba07ca",
     )
 
-    SSHD_VERS = "2.12.0"
+    SSHD_VERS = "2.13.1"
 
     maven_jar(
         name = "sshd-osgi",
         artifact = "org.apache.sshd:sshd-osgi:" + SSHD_VERS,
-        sha1 = "32b8de1cbb722ba75bdf9898e0c41d42af00ce57",
+        sha1 = "50958cc44076749e790d7332021cff546707624c",
     )
 
     maven_jar(
         name = "sshd-sftp",
         artifact = "org.apache.sshd:sshd-sftp:" + SSHD_VERS,
-        sha1 = "0f96f00a07b186ea62838a6a4122e8f4cad44df6",
+        sha1 = "e1b6da4ef604718e32cad59ef32618610da7a170",
     )
 
     maven_jar(
@@ -166,7 +166,7 @@
     maven_jar(
         name = "sshd-mina",
         artifact = "org.apache.sshd:sshd-mina:" + SSHD_VERS,
-        sha1 = "8b202f7d4c0d7b714fd0c93a1352af52aa031149",
+        sha1 = "ff4a9fac41a111d806f6a058d23278b0819da7ce",
     )
 
     maven_jar(