Merge "Fix OperatorPrecedence bug pattern flagged by error prone"
diff --git a/Documentation/dev-bazel.txt b/Documentation/dev-bazel.txt
index 514a4c9..ce4cef4 100644
--- a/Documentation/dev-bazel.txt
+++ b/Documentation/dev-bazel.txt
@@ -35,8 +35,14 @@
 link:https://github.com/bazelbuild/bazelisk[Bazelisk,role=external,window=_blank] is a version
 manager for link:https://bazel.build/[Bazel,role=external,window=_blank], similar to how `nvm`
 manages `npm` versions. It takes care of downloading and installing Bazel itself, so you don't have
-to worry about using the correct version of Bazel. Bazelisk can be installed in different
-ways: link:https://docs.bazel.build/install-bazelisk.html[Install,role=external,window=_blank]
+to worry about using the correct version of Bazel. One particular advantage to
+using Bazelisk is that you can jump between different versions of Gerrit and not
+worry about which version of Bazel you need.
+
+Bazelisk can be installed in different ways:
+link:https://docs.bazel.build/install-bazelisk.html[Bazelisk Installation,role=external,window=_blank].
+To execute the correct version of Bazel using Bazelisk you simply replace
+the `bazel` command with `bazelisk`.
 
 [[java]]
 === Java
@@ -54,7 +60,7 @@
 To build Gerrit with Java 11 language level, run:
 
 ```
-  $ bazel build --java_toolchain=//tools:error_prone_warnings_toolchain_java11 :release
+  $ bazelisk build --java_toolchain=//tools:error_prone_warnings_toolchain_java11 :release
 ```
 
 [[java-17]]
@@ -63,13 +69,13 @@
 Java 17 is supported. To build Gerrit with Java 17, run:
 
 ```
-  $ bazel build --config=java17 :release
+  $ bazelisk build --config=java17 :release
 ```
 
 To run the tests with Java 17, run:
 
 ```
-  $ bazel test --config=java17 //...
+  $ bazelisk test --config=java17 //...
 ```
 
 === Node.js and npm packages
@@ -83,7 +89,7 @@
 To build the Gerrit web application:
 
 ----
-  bazel build gerrit
+  bazelisk build gerrit
 ----
 
 The output executable WAR will be placed in:
@@ -99,7 +105,7 @@
 core plugins and documentation:
 
 ----
-  bazel build release
+  bazelisk build release
 ----
 
 The output executable WAR will be placed in:
@@ -113,7 +119,7 @@
 To build Gerrit in headless mode, i.e. without the Gerrit UI:
 
 ----
-  bazel build headless
+  bazelisk build headless
 ----
 
 The output executable WAR will be placed in:
@@ -127,7 +133,7 @@
 To build the extension, plugin and acceptance-framework JAR files:
 
 ----
-  bazel build api
+  bazelisk build api
 ----
 
 The output archive that contains Java binaries, Java sources and
@@ -153,7 +159,7 @@
 === Plugins
 
 ----
-  bazel build plugins:core
+  bazelisk build plugins:core
 ----
 
 The output JAR files for individual plugins will be placed in:
@@ -171,7 +177,7 @@
 To build a specific plugin:
 
 ----
-  bazel build plugins/<name>
+  bazelisk build plugins/<name>
 ----
 
 The output JAR file will be be placed in:
@@ -216,7 +222,7 @@
 To build only the documentation for testing or static hosting:
 
 ----
-  bazel build Documentation:searchfree
+  bazelisk build Documentation:searchfree
 ----
 
 The html files will be bundled into `searchfree.zip` in this location:
@@ -228,7 +234,7 @@
 To generate HTML files skipping the zip archiving:
 
 ----
-  bazel build Documentation
+  bazelisk build Documentation
 ----
 
 And open `bazel-bin/Documentation/index.html`.
@@ -236,7 +242,7 @@
 To build the Gerrit executable WAR with the documentation included:
 
 ----
-  bazel build withdocs
+  bazelisk build withdocs
 ----
 
 The WAR file will be placed in:
@@ -248,7 +254,7 @@
 Alternatively, one can generate the documentation as flat files:
 
 ----
-  bazel build Documentation:Documentation
+  bazelisk build Documentation:Documentation
 ----
 
 The html, css, js files are placed in:
@@ -260,64 +266,23 @@
 [[tests]]
 == Running Unit Tests
 
-----
-  bazel test --build_tests_only //...
-----
-
-Debugging tests:
+Bazel BUILD files define test targets for Gerrit. You can run all declared
+test targets with:
 
 ----
-  bazel test --test_output=streamed --test_filter=com.gerrit.TestClass.testMethod testTarget
+  bazelisk test --build_tests_only //...
 ----
 
-Debug test example:
+[[testgroups]]
+=== Running Test Groups
+
+To run one or more specific labeled groups of tests:
 
 ----
-  bazel test --test_output=streamed --test_filter=com.google.gerrit.acceptance.api.change.ChangeIT.getAmbiguous //javatests/com/google/gerrit/acceptance/api/change:api_change
+  bazelisk test --test_tag_filters=api,git //...
 ----
 
-To run a specific test group, e.g. the rest-account test group:
-
-----
-  bazel test //javatests/com/google/gerrit/acceptance/rest/account:rest_account
-----
-
-To run only tests that do not use SSH:
-
-----
-  bazel test --test_env=GERRIT_USE_SSH=NO //...
-----
-
-To exclude tests that have been marked as flaky:
-
-----
-  bazel test --test_tag_filters=-flaky //...
-----
-
-To exclude tests that require very recent git client version:
-
-----
-  bazel test --test_tag_filters=-git-protocol-v2 //...
-----
-
-To ignore cached test results:
-
-----
-  bazel test --cache_test_results=NO //...
-----
-
-To run one or more specific groups of tests:
-
-----
-  bazel test --test_tag_filters=api,git //...
-----
-
-To run the tests against a specific index backend (LUCENE, FAKE):
-----
-  bazel test --test_env=GERRIT_INDEX_TYPE=LUCENE //...
-----
-
-The following values are currently supported for the group name:
+The following label values are currently supported for the group name:
 
 * annotation
 * api
@@ -331,11 +296,90 @@
 * server
 * ssh
 
+We can also select tests within a specific BUILD target group. For example
+`javatests/com/google/gerrit/acceptance/rest/account/BUILD` declares a
+rest_account test target group:
+
+----
+  bazelisk test //javatests/com/google/gerrit/acceptance/rest/account:rest_account
+----
+
+[[debugtests]]
+=== Debugging Tests
+
+To debug specific tests you will need to select the test target containing
+that test then use `--test_filter` to select the specific test you want.
+This `--test_filter` is a regex and can be used to select multiple tests
+out of the target:
+
+----
+  bazelisk test --test_output=streamed --test_filter=com.gerrit.TestClass.testMethod testTarget
+----
+
+For example `javatests/com/google/gerrit/acceptance/api/change/BUILD`
+defines a test target group for every `*IT.java` file in the directory.
+We can execute the single `getAmbiguous()` test found in ChangeIT.java using
+this `--test_filter` and target:
+
+----
+  bazelisk test --test_output=streamed \
+    --test_filter=com.google.gerrit.acceptance.api.change.ChangeIT.getAmbiguous \
+    //javatests/com/google/gerrit/acceptance/api/change:ChangeIT
+----
+
+[[additionaltestfiltering]]
+=== Additional Test Filtering
+
+To run only tests that do not use SSH:
+
+----
+  bazelisk test --test_env=GERRIT_USE_SSH=NO //...
+----
+
+To exclude tests that have been marked as flaky:
+
+----
+  bazelisk test --test_tag_filters=-flaky //...
+----
+
+To exclude tests that require very recent git client version:
+
+----
+  bazelisk test --test_tag_filters=-git-protocol-v2 //...
+----
+
+To run the tests against a specific index backend (LUCENE, FAKE):
+----
+  bazelisk test --test_env=GERRIT_INDEX_TYPE=LUCENE //...
+----
+
 Bazel itself supports a multitude of ways to
-link:https://docs.bazel.build/versions/master/guide.html#specifying-targets-to-build[specify targets,role=external,window=_blank]
+link:https://bazel.build/run/build#specifying-build-targets[specify targets,role=external,window=_blank]
 for fine-grained test selection that can be combined with many of the examples
 above.
 
+[[testcaching]]
+=== Test Caching
+
+By default Bazel caches test results and will not reexecute tests unless they
+or their dependencies have been modified. To ignore cached test results and
+force the tests to rerun:
+
+----
+  bazelisk test --cache_test_results=NO //...
+----
+
+[[plugintests]]
+=== Running Plugin Tests
+
+Running tests for Gerrit plugins follows the process above. From within the
+Gerrit project root with the desired plugins checked out into `plugins/` we
+execute Bazel with the appropriate target:
+
+----
+  bazelisk test //plugins/replication/...
+----
+
 [[debugging-tests]]
 == Debugging Unit Tests
 In some cases it may be necessary to debug a test while running it in bazel. For example, when we
@@ -345,7 +389,7 @@
 Example:
 [source,bash]
 ----
-  bazel test --java_debug --test_tag_filters=delete-project //...
+  bazelisk test --java_debug --test_tag_filters=delete-project //...
   ...
   Listening for transport dt_socket at address: 5005
   ...
@@ -364,9 +408,9 @@
 `GERRIT_LOG_LEVEL=debug` environment variable:
 
 ----
-  bazel test --test_filter=com.google.gerrit.server.notedb.ChangeNotesTest \
-  --test_env=GERRIT_LOG_LEVEL=debug \
-  javatests/com/google/gerrit/server:server_tests
+  bazelisk test --test_filter=com.google.gerrit.server.notedb.ChangeNotesTest \
+    --test_env=GERRIT_LOG_LEVEL=debug \
+    javatests/com/google/gerrit/server:server_tests
 ----
 
 The log results can be found in:
@@ -380,7 +424,7 @@
 subsequent builds to run without network access:
 
 ----
-  bazel fetch //...
+  bazelisk fetch //...
 ----
 
 When downloading from behind a proxy (which is common in some corporate
@@ -485,7 +529,7 @@
 
 The `downloaded-artifacts` cache can be relocated by setting the
 `GERRIT_CACHE_HOME` environment variable. The other two can be adjusted with
-`bazel build` options `--repository_cache` and `--disk_cache` respectively.
+`bazelisk build` options `--repository_cache` and `--disk_cache` respectively.
 
 Currently none of these caches have a maximum size limit. See
 link:https://github.com/bazelbuild/bazel/issues/5139[this bazel issue,role=external,window=_blank] for
@@ -547,7 +591,7 @@
 ----
 # Add to ui_npm. Other packages.json can be updated in the same way
 cd $gerrit_repo/polygerrit-ui/app
-bazel run @nodejs//:yarn add $package
+bazelisk run @nodejs//:yarn add $package
 ----
 
 Update the `polygerrit-ui/app/node_modules_licenses/licenses.ts` file. You should add licenses
@@ -577,7 +621,7 @@
 === Update NPM Binaries
 To update a NPM binary the same actions as for a new one must be done (check licenses,
 update `licenses.ts` file, etc...). The only difference is a command to install a package: instead
-of `bazel run @nodejs//:yarn add $package` you should run the `bazel run @nodejs//:yarn upgrade ...`
+of `bazelisk run @nodejs//:yarn add $package` you should run the `bazelisk run @nodejs//:yarn upgrade ...`
 command with correct arguments. You can find the list of arguments in the
 link:https://classic.yarnpkg.com/en/docs/cli/upgrade/[yarn upgrade doc,role=external,window=_blank].
 
@@ -644,7 +688,7 @@
 To use RBE, execute
 
 ```
-bazel test --config=remote \
+bazelisk test --config=remote \
     --remote_instance_name=projects/${PROJECT}/instances/default_instance \
     javatests/...
 ```
diff --git a/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIT.java b/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIT.java
index 5ab9fcb..7eb33b6 100644
--- a/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIT.java
@@ -29,6 +29,7 @@
 import static java.util.stream.Collectors.toMap;
 
 import com.google.common.base.Joiner;
+import com.google.common.base.Splitter;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.gerrit.acceptance.AbstractDaemonTest;
@@ -3135,6 +3136,49 @@
     assertThat(diffInfo).webLinks().isNull();
   }
 
+  @Test
+  public void diffForBinaryFileThatIsNotTouchedInTheChange() throws Exception {
+    String imageFileName1 = "an_image.png";
+    byte[] imageBytes1 = createRgbImage(255, 0, 0);
+    String imageContent1 = new String(imageBytes1, UTF_8);
+    Change.Id changeId1 =
+        changeOperations.newChange().file(imageFileName1).content(imageContent1).create();
+
+    String imageFileName2 = "another_image.png";
+    byte[] imageBytes2 = createRgbImage(0, 255, 0);
+    Change.Id changeId2 =
+        changeOperations
+            .newChange()
+            .childOf()
+            .change(changeId1)
+            .file(imageFileName2)
+            .content(new String(imageBytes2, UTF_8))
+            .create();
+
+    // Since file imageFileName1 was not touched in the second change, trying to get the diff for it
+    // should probably fail with '404 Not Found'.
+    DiffInfo diffInfo = gApi.changes().id(changeId2.get()).current().file(imageFileName1).diff();
+
+    // This should be detected as a binary file, but it isn't.
+    assertThat(diffInfo).binary().isNull();
+
+    // For binary files linesOfA, linesOfB and commonLines are expected to be null, but the content
+    // of the binary file is returned as common lines.
+    ContentEntrySubject contentEntry = assertThat(diffInfo).content().onlyElement();
+    contentEntry.linesOfA().isNull();
+    contentEntry.linesOfB().isNull();
+    contentEntry
+        .commonLines()
+        .containsExactlyElementsIn(Splitter.on("\n").splitToList(imageContent1));
+
+    // For binary file the header list should contain "Binary files differ", but it doesn't.
+    assertThat(diffInfo).diffHeader().isNull();
+
+    assertThat(diffInfo).metaA().isNotNull();
+    assertThat(diffInfo).metaB().isNotNull();
+    assertThat(diffInfo).webLinks().isNull();
+  }
+
   private Registration newEditWebLink() {
     EditWebLink webLink =
         new EditWebLink() {
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts
index 1c9ba8c..fdacf8b 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts
@@ -47,8 +47,7 @@
 import {DiffPreferencesInfo} from '../../../types/diff';
 import {GrDiffHost} from '../../diff/gr-diff-host/gr-diff-host';
 import {GrDiffPreferencesDialog} from '../../diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog';
-import {GrDiffCursor as GrDiffCursorNew} from '../../../embed/diff/gr-diff-cursor/gr-diff-cursor';
-import {GrDiffCursor} from '../../../embed/diff-old/gr-diff-cursor/gr-diff-cursor';
+import {GrDiffCursor} from '../../../embed/diff/gr-diff-cursor/gr-diff-cursor';
 import {GrCursorManager} from '../../shared/gr-cursor-manager/gr-cursor-manager';
 import {ChangeComments} from '../../diff/gr-comment-api/gr-comment-api';
 import {ParsedChangeInfo, PatchSetFile} from '../../../types/types';
@@ -87,7 +86,6 @@
 import {userModelToken} from '../../../models/user/user-model';
 import {pluginLoaderToken} from '../../shared/gr-js-api-interface/gr-plugin-loader';
 import {FileMode, fileModeToString} from '../../../utils/file-util';
-import {isNewDiff} from '../../../embed/diff/gr-diff/gr-diff-utils';
 
 export const DEFAULT_NUM_FILES_SHOWN = 200;
 
@@ -312,8 +310,7 @@
   fileCursor = new GrCursorManager();
 
   // private but used in test
-  // TODO(newdiff-cleanup): Replace once newdiff migration is completed.
-  diffCursor?: GrDiffCursor | GrDiffCursorNew;
+  diffCursor?: GrDiffCursor;
 
   static override get styles() {
     return [
@@ -899,8 +896,7 @@
           );
         }
       });
-    // TODO(newdiff-cleanup): Remove once newdiff migration is completed.
-    this.diffCursor = isNewDiff() ? new GrDiffCursorNew() : new GrDiffCursor();
+    this.diffCursor = new GrDiffCursor();
     this.diffCursor.replaceDiffs(this.diffs);
   }
 
@@ -2318,13 +2314,6 @@
    * Private but used in tests.
    */
   async expandedFilesChanged(oldFiles: Array<PatchSetFile>) {
-    // Clear content for any diffs that are not open so if they get re-opened
-    // the stale content does not flash before it is cleared and reloaded.
-    const collapsedDiffs = this.diffs.filter(
-      diff => this.expandedFiles.findIndex(f => f.path === diff.path) === -1
-    );
-    this.clearCollapsedDiffs(collapsedDiffs);
-
     this.filesExpanded = this.computeExpandedFiles();
 
     const newFiles = this.expandedFiles.filter(
@@ -2341,14 +2330,6 @@
     this.diffCursor?.reInitAndUpdateStops();
   }
 
-  // private but used in test
-  clearCollapsedDiffs(collapsedDiffs: GrDiffHost[]) {
-    for (const diff of collapsedDiffs) {
-      diff.cancel();
-      diff.clearDiffContent();
-    }
-  }
-
   /**
    * Given an array of paths and a NodeList of diff elements, render the diff
    * for each path in order, awaiting the previous render to complete before
@@ -2431,7 +2412,6 @@
     if (this.cancelForEachDiff) {
       this.cancelForEachDiff();
     }
-    this.forEachDiff(d => d.cancel());
   }
 
   /**
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.ts b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.ts
index b2cd430..0f9cf6a 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.ts
@@ -1373,7 +1373,6 @@
       await waitEventLoop();
 
       const renderSpy = sinon.spy(element, 'renderInOrder');
-      const collapseStub = sinon.stub(element, 'clearCollapsedDiffs');
 
       assert.equal(
         queryAndAssert<GrIcon>(element, 'gr-icon').icon,
@@ -1385,7 +1384,6 @@
       // Wait for expandedFilesChanged to finish.
       await waitEventLoop();
 
-      assert.equal(collapseStub.lastCall.args[0].length, 0);
       assert.equal(
         queryAndAssert<GrIcon>(element, 'gr-icon').icon,
         'expand_less'
@@ -1404,11 +1402,9 @@
       );
       assert.equal(renderSpy.callCount, 1);
       assert.isFalse(element.expandedFiles.some(f => f.path === path));
-      assert.equal(collapseStub.lastCall.args[0].length, 1);
     });
 
     test('expandAllDiffs and collapseAllDiffs', async () => {
-      const collapseStub = sinon.stub(element, 'clearCollapsedDiffs');
       assertIsDefined(element.diffCursor);
       const reInitStub = sinon.stub(element.diffCursor, 'reInitAndUpdateStops');
 
@@ -1423,7 +1419,6 @@
       await waitEventLoop();
       assert.equal(element.filesExpanded, FilesExpandedState.ALL);
       assert.isTrue(reInitStub.calledTwice);
-      assert.equal(collapseStub.lastCall.args[0].length, 0);
 
       element.collapseAllDiffs();
       await element.updateComplete;
@@ -1431,7 +1426,6 @@
       await waitEventLoop();
       assert.equal(element.expandedFiles.length, 0);
       assert.equal(element.filesExpanded, FilesExpandedState.NONE);
-      assert.equal(collapseStub.lastCall.args[0].length, 1);
     });
 
     test('expandedFilesChanged', async () => {
@@ -1467,19 +1461,6 @@
       await promise;
     });
 
-    test('clearCollapsedDiffs', () => {
-      // Have to type as any because the type is 'GrDiffHost'
-      // which would require stubbing so many different
-      // methods / properties that it isn't worth it.
-      const diff = {
-        cancel: sinon.stub(),
-        clearDiffContent: sinon.stub(),
-      } as any;
-      element.clearCollapsedDiffs([diff]);
-      assert.isTrue(diff.cancel.calledOnce);
-      assert.isTrue(diff.clearDiffContent.calledOnce);
-    });
-
     test('filesExpanded value updates to correct enum', async () => {
       element.files = [normalize({}, 'foo.bar'), normalize({}, 'baz.bar')];
       await element.updateComplete;
diff --git a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts
index 769b064..7e6e23b 100644
--- a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts
+++ b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts
@@ -7,7 +7,6 @@
 import '../../shared/gr-dialog/gr-dialog';
 import '../../shared/gr-icon/gr-icon';
 import '../../../embed/diff/gr-diff/gr-diff';
-import '../../../embed/diff-old/gr-diff/gr-diff';
 import {navigationToken} from '../../core/gr-navigation/gr-navigation';
 import {
   NumericChangeId,
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts
index caa9f60..1f1ac5c 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts
@@ -6,7 +6,6 @@
 import '../../shared/gr-comment-thread/gr-comment-thread';
 import '../../checks/gr-diff-check-result';
 import '../../../embed/diff/gr-diff/gr-diff';
-import '../../../embed/diff-old/gr-diff/gr-diff';
 import {
   anyLineTooLong,
   getDiffLength,
@@ -46,8 +45,7 @@
   IgnoreWhitespaceType,
   WebLinkInfo,
 } from '../../../types/diff';
-import {GrDiff as GrDiffNew} from '../../../embed/diff/gr-diff/gr-diff';
-import {GrDiff} from '../../../embed/diff-old/gr-diff/gr-diff';
+import {GrDiff} from '../../../embed/diff/gr-diff/gr-diff';
 import {DiffViewMode, Side, CommentSide} from '../../../constants/constants';
 import {FilesWebLinks} from '../gr-patch-range-select/gr-patch-range-select';
 import {KnownExperimentId} from '../../../services/flags/flags';
@@ -139,9 +137,8 @@
  */
 @customElement('gr-diff-host')
 export class GrDiffHost extends LitElement {
-  // TODO(newdiff-cleanup): Replace once newdiff migration is completed.
   @query('#diff')
-  diffElement?: GrDiff | GrDiffNew;
+  diffElement?: GrDiff;
 
   @property({type: Number})
   changeNum?: NumericChangeId;
@@ -560,8 +557,6 @@
     // TODO: Find better names for these 3 clear/cancel methods. Ideally the
     // <gr-diff-host> should not re-used at all for another diff rendering pass.
     this.clear();
-    this.cancel();
-    this.clearDiffContent();
     assertIsDefined(this.path, 'path');
     assertIsDefined(this.changeNum, 'changeNum');
     this.diff = undefined;
@@ -815,11 +810,6 @@
     };
   }
 
-  /** Cancel any remaining diff builder rendering work. */
-  cancel() {
-    this.diffElement?.cancel();
-  }
-
   getCursorStops() {
     assertIsDefined(this.diffElement);
     return this.diffElement.getCursorStops();
@@ -864,10 +854,6 @@
     this.blame = null;
   }
 
-  clearDiffContent() {
-    this.diffElement?.clearDiffContent();
-  }
-
   toggleAllContext() {
     assertIsDefined(this.diffElement);
     this.diffElement.toggleAllContext();
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.ts b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.ts
index d56f63f..9dabe1d 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.ts
@@ -59,7 +59,6 @@
   CommentsModel,
   commentsModelToken,
 } from '../../../models/comments/comments-model';
-import {isNewDiff} from '../../../embed/diff/gr-diff/gr-diff-utils';
 
 suite('gr-diff-host tests', () => {
   let element: GrDiffHost;
@@ -154,25 +153,6 @@
     );
   });
 
-  test('reload() cancels before network resolves', async () => {
-    if (isNewDiff()) return;
-    assertIsDefined(element.diffElement);
-    const cancelStub = sinon.stub(element.diffElement, 'cancel');
-
-    // Stub the network calls into requests that never resolve.
-    sinon.stub(element, 'getDiff').callsFake(() => new Promise(() => {}));
-    element.patchRange = createPatchRange();
-    element.change = createChange();
-    element.prefs = undefined;
-
-    // Needs to be set to something first for it to cancel.
-    element.diff = createDiff();
-    await element.updateComplete;
-
-    element.reload();
-    assert.isTrue(cancelStub.called);
-  });
-
   test('prefetch getDiff', async () => {
     getDiffRestApiStub.returns(Promise.resolve(createDiff()));
     element.changeNum = 123 as NumericChangeId;
@@ -558,15 +538,6 @@
     assert.isTrue(showAuthRequireSpy.called);
   });
 
-  test('delegates cancel()', () => {
-    assertIsDefined(element.diffElement);
-    const stub = sinon.stub(element.diffElement, 'cancel');
-    element.patchRange = createPatchRange();
-    element.cancel();
-    assert.isTrue(stub.calledOnce);
-    assert.equal(stub.lastCall.args.length, 0);
-  });
-
   test('delegates getCursorStops()', () => {
     const returnValue = [document.createElement('b')];
     assertIsDefined(element.diffElement);
@@ -666,14 +637,6 @@
       });
   });
 
-  test('delegates clearDiffContent()', () => {
-    assertIsDefined(element.diffElement);
-    const stub = sinon.stub(element.diffElement, 'clearDiffContent');
-    element.clearDiffContent();
-    assert.isTrue(stub.calledOnce);
-    assert.equal(stub.lastCall.args.length, 0);
-  });
-
   test('delegates toggleAllContext()', () => {
     assertIsDefined(element.diffElement);
     const stub = sinon.stub(element.diffElement, 'toggleAllContext');
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
index c76c9d6..246e7ed 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
@@ -56,8 +56,7 @@
   FilesWebLinks,
   PatchRangeChangeEvent,
 } from '../gr-patch-range-select/gr-patch-range-select';
-import {GrDiffCursor as GrDiffCursorNew} from '../../../embed/diff/gr-diff-cursor/gr-diff-cursor';
-import {GrDiffCursor} from '../../../embed/diff-old/gr-diff-cursor/gr-diff-cursor';
+import {GrDiffCursor} from '../../../embed/diff/gr-diff-cursor/gr-diff-cursor';
 import {CommentSide, DiffViewMode, Side} from '../../../constants/constants';
 import {GrApplyFixDialog} from '../gr-apply-fix-dialog/gr-apply-fix-dialog';
 import {OpenFixPreviewEvent, ValueChangedEvent} from '../../../types/events';
@@ -104,7 +103,6 @@
   FileNameToNormalizedFileInfoMap,
   filesModelToken,
 } from '../../../models/change/files-model';
-import {isNewDiff} from '../../../embed/diff/gr-diff/gr-diff-utils';
 import {isImageDiff} from '../../../utils/diff-util';
 import {formStyles} from '../../../styles/form-styles';
 
@@ -258,9 +256,8 @@
 
   private throttledToggleFileReviewed?: (e: KeyboardEvent) => void;
 
-  // TODO(newdiff-cleanup): Replace once newdiff migration is completed.
   @state()
-  cursor?: GrDiffCursor | GrDiffCursorNew;
+  cursor?: GrDiffCursor;
 
   private readonly shortcutsController = new ShortcutController(this);
 
@@ -697,8 +694,7 @@
       this.handleToggleFileReviewed()
     );
     this.addEventListener('open-fix-preview', e => this.onOpenFixPreview(e));
-    // TODO(newdiff-cleanup): Remove once newdiff migration is completed.
-    this.cursor = isNewDiff() ? new GrDiffCursorNew() : new GrDiffCursor();
+    this.cursor = new GrDiffCursor();
     if (this.diffHost) this.reInitCursor();
     window.addEventListener('scroll', this.updateSidebarHeight);
     window.addEventListener('resize', this.updateSidebarHeight);
diff --git a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
index f04c233..0b03581 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
@@ -8,7 +8,6 @@
 import '../gr-comment/gr-comment';
 import '../gr-icon/gr-icon';
 import '../../../embed/diff/gr-diff/gr-diff';
-import '../../../embed/diff-old/gr-diff/gr-diff';
 import '../gr-copy-clipboard/gr-copy-clipboard';
 import {css, html, nothing, LitElement, PropertyValues} from 'lit';
 import {
diff --git a/polygerrit-ui/app/elements/shared/gr-suggestion-diff-preview/gr-suggestion-diff-preview_test.ts b/polygerrit-ui/app/elements/shared/gr-suggestion-diff-preview/gr-suggestion-diff-preview_test.ts
index dd6d62d..86be868 100644
--- a/polygerrit-ui/app/elements/shared/gr-suggestion-diff-preview/gr-suggestion-diff-preview_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-suggestion-diff-preview/gr-suggestion-diff-preview_test.ts
@@ -100,6 +100,15 @@
     };
     await element.updateComplete;
 
-    assert.shadowDom.equal(element, /* HTML */ '<gr-diff></gr-diff>');
+    assert.shadowDom.equal(
+      element,
+      /* HTML */ `
+        <gr-diff
+          class="disable-context-control-buttons hide-line-length-indicator"
+        >
+        </gr-diff>
+      `,
+      {ignoreAttributes: ['style']}
+    );
   });
 });
diff --git a/polygerrit-ui/app/embed/diff-old/gr-context-controls/gr-context-controls-section.ts b/polygerrit-ui/app/embed/diff-old/gr-context-controls/gr-context-controls-section.ts
deleted file mode 100644
index e558295..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-context-controls/gr-context-controls-section.ts
+++ /dev/null
@@ -1,138 +0,0 @@
-/**
- * @license
- * Copyright 2022 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import '../../../elements/shared/gr-button/gr-button';
-import {html, LitElement} from 'lit';
-import {property, state} from 'lit/decorators.js';
-import {DiffInfo, DiffViewMode, RenderPreferences} from '../../../api/diff';
-import {GrDiffGroup, GrDiffGroupType} from '../gr-diff/gr-diff-group';
-import {diffClasses, isNewDiff} from '../../diff/gr-diff/gr-diff-utils';
-import {getShowConfig} from './gr-context-controls';
-import {ifDefined} from 'lit/directives/if-defined.js';
-import {when} from 'lit/directives/when.js';
-
-export class GrContextControlsSection extends LitElement {
-  /** Should context controls be rendered for expanding above the section? */
-  @property({type: Boolean}) showAbove = false;
-
-  /** Should context controls be rendered for expanding below the section? */
-  @property({type: Boolean}) showBelow = false;
-
-  /** Must be of type GrDiffGroupType.CONTEXT_CONTROL. */
-  @property({type: Object})
-  group?: GrDiffGroup;
-
-  @property({type: Object})
-  diff?: DiffInfo;
-
-  @property({type: Object})
-  renderPrefs?: RenderPreferences;
-
-  /**
-   * Semantic DOM diff testing does not work with just table fragments, so when
-   * running such tests the render() method has to wrap the DOM in a proper
-   * <table> element.
-   */
-  @state()
-  addTableWrapperForTesting = false;
-
-  /**
-   * The browser API for handling selection does not (yet) work for selection
-   * across multiple shadow DOM elements. So we are rendering gr-diff components
-   * into the light DOM instead of the shadow DOM by overriding this method,
-   * which was the recommended workaround by the lit team.
-   * See also https://github.com/WICG/webcomponents/issues/79.
-   */
-  override createRenderRoot() {
-    return this;
-  }
-
-  private renderPaddingRow(whereClass: 'above' | 'below') {
-    if (!this.showAbove && whereClass === 'above') return;
-    if (!this.showBelow && whereClass === 'below') return;
-    const modeClass = this.isSideBySide() ? 'side-by-side' : 'unified';
-    const type = this.isSideBySide()
-      ? GrDiffGroupType.CONTEXT_CONTROL
-      : undefined;
-    return html`
-      <tr
-        class=${diffClasses('contextBackground', modeClass, whereClass)}
-        left-type=${ifDefined(type)}
-        right-type=${ifDefined(type)}
-      >
-        <td class=${diffClasses('blame')} data-line-number="0"></td>
-        <td class=${diffClasses('contextLineNum')}></td>
-        ${when(
-          this.isSideBySide(),
-          () => html`
-            <td class=${diffClasses('sign')}></td>
-            <td class=${diffClasses()}></td>
-          `
-        )}
-        <td class=${diffClasses('contextLineNum')}></td>
-        ${when(
-          this.isSideBySide(),
-          () => html`<td class=${diffClasses('sign')}></td>`
-        )}
-        <td class=${diffClasses()}></td>
-      </tr>
-    `;
-  }
-
-  private isSideBySide() {
-    return this.renderPrefs?.view_mode !== DiffViewMode.UNIFIED;
-  }
-
-  private createContextControlRow() {
-    // Note that <td> table cells that have `display: none` don't count!
-    const colspan = this.renderPrefs?.show_sign_col ? '5' : '3';
-    const showConfig = getShowConfig(this.showAbove, this.showBelow);
-    return html`
-      <tr class=${diffClasses('dividerRow', `show-${showConfig}`)}>
-        <td class=${diffClasses('blame')} data-line-number="0"></td>
-        ${when(
-          this.isSideBySide(),
-          () => html`<td class=${diffClasses()}></td>`
-        )}
-        <td class=${diffClasses('dividerCell')} colspan=${colspan}>
-          <gr-context-controls
-            class=${diffClasses()}
-            .diff=${this.diff}
-            .renderPreferences=${this.renderPrefs}
-            .group=${this.group}
-            .showConfig=${showConfig}
-          >
-          </gr-context-controls>
-        </td>
-      </tr>
-    `;
-  }
-
-  override render() {
-    const rows = html`
-      ${this.renderPaddingRow('above')} ${this.createContextControlRow()}
-      ${this.renderPaddingRow('below')}
-    `;
-    if (this.addTableWrapperForTesting) {
-      return html`<table>
-        ${rows}
-      </table>`;
-    }
-    return rows;
-  }
-}
-
-if (!isNewDiff()) {
-  customElements.define(
-    'gr-context-controls-section',
-    GrContextControlsSection
-  );
-}
-
-declare global {
-  interface HTMLElementTagNameMap {
-    'gr-context-controls-section': LitElement;
-  }
-}
diff --git a/polygerrit-ui/app/embed/diff-old/gr-context-controls/gr-context-controls-section_test.ts b/polygerrit-ui/app/embed/diff-old/gr-context-controls/gr-context-controls-section_test.ts
deleted file mode 100644
index 6a557fc..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-context-controls/gr-context-controls-section_test.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * @license
- * Copyright 2022 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import '../../../test/common-test-setup';
-import './gr-context-controls-section';
-import {GrContextControlsSection} from './gr-context-controls-section';
-import {fixture, html, assert} from '@open-wc/testing';
-
-suite('gr-context-controls-section test', () => {
-  let element: GrContextControlsSection;
-
-  setup(async () => {
-    element = await fixture<GrContextControlsSection>(
-      html`<gr-context-controls-section></gr-context-controls-section>`
-    );
-    element.addTableWrapperForTesting = true;
-    await element.updateComplete;
-  });
-
-  test('render: normal with showAbove and showBelow', async () => {
-    element.showAbove = true;
-    element.showBelow = true;
-    await element.updateComplete;
-    assert.lightDom.equal(
-      element,
-      /* HTML */ `
-        <table>
-          <tbody>
-            <tr
-              class="above contextBackground gr-diff side-by-side"
-              left-type="contextControl"
-              right-type="contextControl"
-            >
-              <td class="blame gr-diff" data-line-number="0"></td>
-              <td class="contextLineNum gr-diff"></td>
-              <td class="gr-diff sign"></td>
-              <td class="gr-diff"></td>
-              <td class="contextLineNum gr-diff"></td>
-              <td class="gr-diff sign"></td>
-              <td class="gr-diff"></td>
-            </tr>
-            <tr class="dividerRow gr-diff show-both">
-              <td class="blame gr-diff" data-line-number="0"></td>
-              <td class="gr-diff"></td>
-              <td class="dividerCell gr-diff" colspan="3">
-                <gr-context-controls class="gr-diff" showconfig="both">
-                </gr-context-controls>
-              </td>
-            </tr>
-            <tr
-              class="below contextBackground gr-diff side-by-side"
-              left-type="contextControl"
-              right-type="contextControl"
-            >
-              <td class="blame gr-diff" data-line-number="0"></td>
-              <td class="contextLineNum gr-diff"></td>
-              <td class="gr-diff sign"></td>
-              <td class="gr-diff"></td>
-              <td class="contextLineNum gr-diff"></td>
-              <td class="gr-diff sign"></td>
-              <td class="gr-diff"></td>
-            </tr>
-          </tbody>
-        </table>
-      `
-    );
-  });
-});
diff --git a/polygerrit-ui/app/embed/diff-old/gr-context-controls/gr-context-controls.ts b/polygerrit-ui/app/embed/diff-old/gr-context-controls/gr-context-controls.ts
deleted file mode 100644
index e4afd23..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-context-controls/gr-context-controls.ts
+++ /dev/null
@@ -1,537 +0,0 @@
-/**
- * @license
- * Copyright 2021 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import '@polymer/paper-button/paper-button';
-import '@polymer/paper-card/paper-card';
-import '@polymer/paper-checkbox/paper-checkbox';
-import '@polymer/paper-dropdown-menu/paper-dropdown-menu';
-import '@polymer/paper-fab/paper-fab';
-import '@polymer/paper-icon-button/paper-icon-button';
-import '@polymer/paper-item/paper-item';
-import '@polymer/paper-listbox/paper-listbox';
-import '@polymer/paper-tooltip/paper-tooltip';
-import {of, EMPTY, Subject} from 'rxjs';
-import {switchMap, delay} from 'rxjs/operators';
-
-import '../../../elements/shared/gr-button/gr-button';
-import {pluralize} from '../../../utils/string-util';
-import {fire} from '../../../utils/event-util';
-import {DiffInfo} from '../../../types/diff';
-import {assertIsDefined} from '../../../utils/common-util';
-import {css, html, LitElement, TemplateResult} from 'lit';
-import {property} from 'lit/decorators.js';
-import {subscribe} from '../../../elements/lit/subscription-controller';
-
-import {
-  ContextButtonType,
-  DiffContextButtonHoveredDetail,
-  RenderPreferences,
-  SyntaxBlock,
-} from '../../../api/diff';
-
-import {GrDiffGroup, hideInContextControl} from '../gr-diff/gr-diff-group';
-import {isNewDiff} from '../../diff/gr-diff/gr-diff-utils';
-
-declare global {
-  interface HTMLElementEventMap {
-    'diff-context-button-hovered': CustomEvent<DiffContextButtonHoveredDetail>;
-  }
-}
-
-const PARTIAL_CONTEXT_AMOUNT = 10;
-
-/**
- * Traverses a hierarchical structure of syntax blocks and
- * finds the most local/nested block that can be associated line.
- * It finds the closest block that contains the whole line and
- * returns the whole path from the syntax layer (blocks) sent as parameter
- * to the most nested block - the complete path from the top to bottom layer of
- * a syntax tree. Example: [myNamespace, MyClass, myMethod1, aLocalFunctionInsideMethod1]
- *
- * @param lineNum line number for the targeted line.
- * @param blocks Blocks for a specific syntax level in the file (to allow recursive calls)
- */
-function findBlockTreePathForLine(
-  lineNum: number,
-  blocks?: SyntaxBlock[]
-): SyntaxBlock[] {
-  const containingBlock = blocks?.find(
-    ({range}) => range.start_line < lineNum && range.end_line > lineNum
-  );
-  if (!containingBlock) return [];
-  const innerPathInChild = findBlockTreePathForLine(
-    lineNum,
-    containingBlock?.children
-  );
-  return [containingBlock].concat(innerPathInChild);
-}
-
-export type GrContextControlsShowConfig = 'above' | 'below' | 'both';
-
-export function getShowConfig(
-  showAbove: boolean,
-  showBelow: boolean
-): GrContextControlsShowConfig {
-  if (showAbove && !showBelow) return 'above';
-  if (!showAbove && showBelow) return 'below';
-
-  // Note that !showAbove && !showBelow also intentionally returns 'both'.
-  // This means the file is completely collapsed, which is unusual, but at least
-  // happens in one test.
-  return 'both';
-}
-
-export class GrContextControls extends LitElement {
-  @property({type: Object}) renderPreferences?: RenderPreferences;
-
-  @property({type: Object}) diff?: DiffInfo;
-
-  @property({type: Object}) group?: GrDiffGroup;
-
-  @property({type: String, reflect: true})
-  showConfig: GrContextControlsShowConfig = 'both';
-
-  private expandButtonsHover = new Subject<{
-    eventType: 'enter' | 'leave';
-    buttonType: ContextButtonType;
-    linesToExpand: number;
-  }>();
-
-  static override get styles() {
-    return [
-      css`
-        :host {
-          display: flex;
-          justify-content: center;
-          flex-direction: column;
-          position: relative;
-        }
-
-        :host([showConfig='above']) {
-          justify-content: flex-end;
-          margin-top: calc(-1px - var(--line-height-normal) - var(--spacing-s));
-          margin-bottom: var(--gr-context-controls-margin-bottom);
-          height: calc(var(--line-height-normal) + var(--spacing-s));
-          .horizontalFlex {
-            align-items: end;
-          }
-        }
-
-        :host([showConfig='below']) {
-          justify-content: flex-start;
-          margin-top: 1px;
-          margin-bottom: calc(
-            0px - var(--line-height-normal) - var(--spacing-s)
-          );
-          .horizontalFlex {
-            align-items: start;
-          }
-        }
-
-        :host([showConfig='both']) {
-          margin-top: calc(0px - var(--line-height-normal) - var(--spacing-s));
-          margin-bottom: calc(
-            0px - var(--line-height-normal) - var(--spacing-s)
-          );
-          height: calc(
-            2 * var(--line-height-normal) + 2 * var(--spacing-s) +
-              var(--divider-height)
-          );
-          .horizontalFlex {
-            align-items: center;
-          }
-        }
-
-        .contextControlButton {
-          background-color: var(--default-button-background-color);
-          font: var(--context-control-button-font, inherit);
-        }
-
-        paper-button {
-          text-transform: none;
-          align-items: center;
-          background-color: var(--background-color);
-          font-family: inherit;
-          margin: var(--margin, 0);
-          min-width: var(--border, 0);
-          color: var(--diff-context-control-color);
-          border: solid var(--border-color);
-          border-width: 1px;
-          border-radius: var(--border-radius);
-          padding: var(--spacing-s) var(--spacing-l);
-        }
-
-        paper-button:hover {
-          /* same as defined in gr-button */
-          background: rgba(0, 0, 0, 0.12);
-        }
-        paper-button:focus-visible {
-          /* paper-button sets this to 0, thus preventing focus-based styling. */
-          outline-width: 1px;
-        }
-
-        .aboveBelowButtons {
-          display: flex;
-          flex-direction: column;
-          justify-content: center;
-          margin-left: var(--spacing-m);
-          position: relative;
-        }
-        .aboveBelowButtons:first-child {
-          margin-left: 0;
-          /* Places a default background layer behind the "all button" that can have opacity */
-          background-color: var(--default-button-background-color);
-        }
-
-        .horizontalFlex {
-          display: flex;
-          justify-content: center;
-          align-items: var(
-            --gr-context-controls-horizontal-align-items,
-            center
-          );
-        }
-
-        .aboveButton {
-          border-bottom-width: 0;
-          border-bottom-right-radius: 0;
-          border-bottom-left-radius: 0;
-          padding: var(--spacing-xxs) var(--spacing-l);
-        }
-        .belowButton {
-          border-top-width: 0;
-          border-top-left-radius: 0;
-          border-top-right-radius: 0;
-          padding: var(--spacing-xxs) var(--spacing-l);
-          margin-top: calc(var(--divider-height) + 2 * var(--spacing-xxs));
-        }
-        .belowButton:first-child {
-          margin-top: 0;
-        }
-        .breadcrumbTooltip {
-          white-space: nowrap;
-        }
-      `,
-    ];
-  }
-
-  constructor() {
-    super();
-    this.setupButtonHoverHandler();
-  }
-
-  private showBoth() {
-    return this.showConfig === 'both';
-  }
-
-  private showAbove() {
-    return this.showBoth() || this.showConfig === 'above';
-  }
-
-  private showBelow() {
-    return this.showBoth() || this.showConfig === 'below';
-  }
-
-  private setupButtonHoverHandler() {
-    subscribe(
-      this,
-      () =>
-        this.expandButtonsHover.pipe(
-          switchMap(e => {
-            if (e.eventType === 'leave') {
-              // cancel any previous delay
-              // for mouse enter
-              return EMPTY;
-            }
-            return of(e).pipe(delay(500));
-          })
-        ),
-      ({buttonType, linesToExpand}) => {
-        fire(this, 'diff-context-button-hovered', {
-          buttonType,
-          linesToExpand,
-        });
-      }
-    );
-  }
-
-  private numLines() {
-    assertIsDefined(this.group);
-    // In context groups, there is the same number of lines left and right
-    const left = this.group.lineRange.left;
-    // Both start and end inclusive, so we need to add 1.
-    return left.end_line - left.start_line + 1;
-  }
-
-  private createExpandAllButtonContainer() {
-    return html` <div class="gr-diff aboveBelowButtons fullExpansion">
-      ${this.createContextButton(ContextButtonType.ALL, this.numLines())}
-    </div>`;
-  }
-
-  /**
-   * Creates a specific expansion button (e.g. +X common lines, +10, +Block).
-   */
-  private createContextButton(
-    type: ContextButtonType,
-    linesToExpand: number,
-    tooltip?: TemplateResult
-  ) {
-    if (!this.group) return;
-    let text = '';
-    let groups: GrDiffGroup[] = []; // The groups that replace this one if tapped.
-    let ariaLabel = '';
-    let classes = 'contextControlButton showContext ';
-
-    if (type === ContextButtonType.ALL) {
-      text = `+${pluralize(linesToExpand, 'common line')}`;
-      ariaLabel = `Show ${pluralize(linesToExpand, 'common line')}`;
-      classes += this.showBoth()
-        ? 'centeredButton'
-        : this.showAbove()
-        ? 'aboveButton'
-        : 'belowButton';
-      if (this.group?.hasSkipGroup()) {
-        // Expanding content would require load of more data
-        text += ' (too large)';
-      }
-      groups.push(...this.group.contextGroups);
-    } else if (type === ContextButtonType.ABOVE) {
-      groups = hideInContextControl(
-        this.group.contextGroups,
-        linesToExpand,
-        this.numLines()
-      );
-      text = `+${linesToExpand}`;
-      classes += 'aboveButton';
-      ariaLabel = `Show ${pluralize(linesToExpand, 'line')} above`;
-    } else if (type === ContextButtonType.BELOW) {
-      groups = hideInContextControl(
-        this.group.contextGroups,
-        0,
-        this.numLines() - linesToExpand
-      );
-      text = `+${linesToExpand}`;
-      classes += 'belowButton';
-      ariaLabel = `Show ${pluralize(linesToExpand, 'line')} below`;
-    } else if (type === ContextButtonType.BLOCK_ABOVE) {
-      groups = hideInContextControl(
-        this.group.contextGroups,
-        linesToExpand,
-        this.numLines()
-      );
-      text = '+Block';
-      classes += 'aboveButton';
-      ariaLabel = 'Show block above';
-    } else if (type === ContextButtonType.BLOCK_BELOW) {
-      groups = hideInContextControl(
-        this.group.contextGroups,
-        0,
-        this.numLines() - linesToExpand
-      );
-      text = '+Block';
-      classes += 'belowButton';
-      ariaLabel = 'Show block below';
-    }
-    const expandHandler = this.createExpansionHandler(
-      linesToExpand,
-      type,
-      groups
-    );
-
-    const mouseHandler = (eventType: 'enter' | 'leave') => {
-      this.expandButtonsHover.next({
-        eventType,
-        buttonType: type,
-        linesToExpand,
-      });
-    };
-
-    const button = html` <paper-button
-      class=${classes}
-      aria-label=${ariaLabel}
-      @click=${expandHandler}
-      @mouseenter=${() => mouseHandler('enter')}
-      @mouseleave=${() => mouseHandler('leave')}
-    >
-      <span class="showContext">${text}</span>
-      ${tooltip}
-    </paper-button>`;
-    return button;
-  }
-
-  private createExpansionHandler(
-    linesToExpand: number,
-    type: ContextButtonType,
-    groups: GrDiffGroup[]
-  ) {
-    return (e: Event) => {
-      assertIsDefined(this.group);
-      e.stopPropagation();
-      if (type === ContextButtonType.ALL && this.group?.hasSkipGroup()) {
-        fire(this, 'content-load-needed', {
-          lineRange: this.group.lineRange,
-        });
-      } else {
-        fire(this, 'diff-context-expanded', {
-          numLines: this.numLines(),
-          buttonType: type,
-          expandedLines: linesToExpand,
-        });
-        fire(this, 'diff-context-expanded-internal', {
-          contextGroup: this.group,
-          groups,
-          numLines: this.numLines(),
-          buttonType: type,
-          expandedLines: linesToExpand,
-        });
-      }
-    };
-  }
-
-  private showPartialLinks() {
-    return this.numLines() > PARTIAL_CONTEXT_AMOUNT;
-  }
-
-  /**
-   * Creates a container div with partial (+10) expansion buttons (above and/or below).
-   */
-  private createPartialExpansionButtons() {
-    if (!this.showPartialLinks()) {
-      return undefined;
-    }
-    let aboveButton;
-    let belowButton;
-    if (this.showAbove()) {
-      aboveButton = this.createContextButton(
-        ContextButtonType.ABOVE,
-        PARTIAL_CONTEXT_AMOUNT
-      );
-    }
-    if (this.showBelow()) {
-      belowButton = this.createContextButton(
-        ContextButtonType.BELOW,
-        PARTIAL_CONTEXT_AMOUNT
-      );
-    }
-    return aboveButton || belowButton
-      ? html` <div class="aboveBelowButtons partialExpansion">
-          ${aboveButton} ${belowButton}
-        </div>`
-      : undefined;
-  }
-
-  /**
-   * Creates a container div with block expansion buttons (above and/or below).
-   */
-  private createBlockExpansionButtons() {
-    assertIsDefined(this.group, 'group');
-    if (
-      !this.showPartialLinks() ||
-      !this.renderPreferences?.use_block_expansion ||
-      this.group?.hasSkipGroup()
-    ) {
-      return undefined;
-    }
-    let aboveBlockButton;
-    let belowBlockButton;
-    if (this.showAbove()) {
-      aboveBlockButton = this.createBlockButton(
-        ContextButtonType.BLOCK_ABOVE,
-        this.numLines(),
-        this.group.lineRange.right.start_line - 1
-      );
-    }
-    if (this.showBelow()) {
-      belowBlockButton = this.createBlockButton(
-        ContextButtonType.BLOCK_BELOW,
-        this.numLines(),
-        this.group.lineRange.right.end_line + 1
-      );
-    }
-    if (aboveBlockButton || belowBlockButton) {
-      return html` <div class="aboveBelowButtons blockExpansion">
-        ${aboveBlockButton} ${belowBlockButton}
-      </div>`;
-    }
-    return undefined;
-  }
-
-  private createBlockButtonTooltip(
-    buttonType: ContextButtonType,
-    syntaxPath: SyntaxBlock[],
-    linesToExpand: number
-  ) {
-    // Create breadcrumb string:
-    // myNamespace > MyClass > myMethod1 > aLocalFunctionInsideMethod1 > (anonymous)
-    const tooltipText = syntaxPath.length
-      ? syntaxPath.map(b => b.name || '(anonymous)').join(' > ')
-      : `${linesToExpand} common lines`;
-
-    const position =
-      buttonType === ContextButtonType.BLOCK_ABOVE ? 'top' : 'bottom';
-    return html`<paper-tooltip offset="10" position=${position}
-      ><div class="breadcrumbTooltip">${tooltipText}</div></paper-tooltip
-    >`;
-  }
-
-  private createBlockButton(
-    buttonType: ContextButtonType,
-    numLines: number,
-    referenceLine: number
-  ) {
-    if (!this.diff?.meta_b) return;
-    const syntaxTree = this.diff.meta_b.syntax_tree;
-    const outlineSyntaxPath = findBlockTreePathForLine(
-      referenceLine,
-      syntaxTree
-    );
-    let linesToExpand = numLines;
-    if (outlineSyntaxPath.length) {
-      const {range} = outlineSyntaxPath[outlineSyntaxPath.length - 1];
-      const targetLine =
-        buttonType === ContextButtonType.BLOCK_ABOVE
-          ? range.end_line
-          : range.start_line;
-      const distanceToTargetLine = Math.abs(targetLine - referenceLine);
-      if (distanceToTargetLine < numLines) {
-        linesToExpand = distanceToTargetLine;
-      }
-    }
-    const tooltip = this.createBlockButtonTooltip(
-      buttonType,
-      outlineSyntaxPath,
-      linesToExpand
-    );
-    return this.createContextButton(buttonType, linesToExpand, tooltip);
-  }
-
-  private hasValidProperties() {
-    return !!(this.diff && this.group?.contextGroups?.length);
-  }
-
-  override render() {
-    if (!this.hasValidProperties()) {
-      console.error('Invalid properties for gr-context-controls!');
-      return html`<p>invalid properties</p>`;
-    }
-    return html`
-      <div class="horizontalFlex">
-        ${this.createExpandAllButtonContainer()}
-        ${this.createPartialExpansionButtons()}
-        ${this.createBlockExpansionButtons()}
-      </div>
-    `;
-  }
-}
-if (!isNewDiff()) {
-  customElements.define('gr-context-controls', GrContextControls);
-}
-
-declare global {
-  interface HTMLElementTagNameMap {
-    'gr-context-controls': LitElement;
-  }
-}
diff --git a/polygerrit-ui/app/embed/diff-old/gr-context-controls/gr-context-controls_test.ts b/polygerrit-ui/app/embed/diff-old/gr-context-controls/gr-context-controls_test.ts
deleted file mode 100644
index 196afe5..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-context-controls/gr-context-controls_test.ts
+++ /dev/null
@@ -1,374 +0,0 @@
-/**
- * @license
- * Copyright 2021 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import '../../../test/common-test-setup';
-import '../gr-diff/gr-diff-group';
-import './gr-context-controls';
-import {GrContextControls} from './gr-context-controls';
-
-import {GrDiffLine} from '../gr-diff/gr-diff-line';
-import {GrDiffGroup, GrDiffGroupType} from '../gr-diff/gr-diff-group';
-import {
-  DiffFileMetaInfo,
-  DiffInfo,
-  GrDiffLineType,
-  SyntaxBlock,
-} from '../../../api/diff';
-import {fixture, html, assert} from '@open-wc/testing';
-import {waitEventLoop} from '../../../test/test-utils';
-
-suite('gr-context-control tests', () => {
-  let element: GrContextControls;
-
-  setup(async () => {
-    element = document.createElement(
-      'gr-context-controls'
-    ) as GrContextControls;
-    element.diff = {content: []} as any as DiffInfo;
-    element.renderPreferences = {};
-    const div = await fixture(html`<div></div>`);
-    div.appendChild(element);
-    await waitEventLoop();
-  });
-
-  function createContextGroup(options: {offset?: number; count?: number}) {
-    const offset = options.offset || 0;
-    const numLines = options.count || 10;
-    const lines = [];
-    for (let i = 0; i < numLines; i++) {
-      const line = new GrDiffLine(GrDiffLineType.BOTH);
-      line.beforeNumber = offset + i + 1;
-      line.afterNumber = offset + i + 1;
-      line.text = 'lorem upsum';
-      lines.push(line);
-    }
-    return new GrDiffGroup({
-      type: GrDiffGroupType.CONTEXT_CONTROL,
-      contextGroups: [new GrDiffGroup({type: GrDiffGroupType.BOTH, lines})],
-    });
-  }
-
-  test('no +10 buttons for 10 or less lines', async () => {
-    element.group = createContextGroup({count: 10});
-
-    await waitEventLoop();
-
-    const buttons = element.shadowRoot!.querySelectorAll(
-      'paper-button.showContext'
-    );
-    assert.equal(buttons.length, 1);
-    assert.equal(buttons[0].textContent!.trim(), '+10 common lines');
-  });
-
-  test('context control at the top', async () => {
-    element.group = createContextGroup({offset: 0, count: 20});
-    element.showConfig = 'below';
-
-    await waitEventLoop();
-
-    const buttons = element.shadowRoot!.querySelectorAll(
-      'paper-button.showContext'
-    );
-
-    assert.equal(buttons.length, 2);
-    assert.equal(buttons[0].textContent!.trim(), '+20 common lines');
-    assert.equal(buttons[1].textContent!.trim(), '+10');
-
-    assert.include([...buttons[0].classList.values()], 'belowButton');
-    assert.include([...buttons[1].classList.values()], 'belowButton');
-  });
-
-  test('context control in the middle', async () => {
-    element.group = createContextGroup({offset: 10, count: 20});
-    element.showConfig = 'both';
-
-    await waitEventLoop();
-
-    const buttons = element.shadowRoot!.querySelectorAll(
-      'paper-button.showContext'
-    );
-
-    assert.equal(buttons.length, 3);
-    assert.equal(buttons[0].textContent!.trim(), '+20 common lines');
-    assert.equal(buttons[1].textContent!.trim(), '+10');
-    assert.equal(buttons[2].textContent!.trim(), '+10');
-
-    assert.include([...buttons[0].classList.values()], 'centeredButton');
-    assert.include([...buttons[1].classList.values()], 'aboveButton');
-    assert.include([...buttons[2].classList.values()], 'belowButton');
-  });
-
-  test('context control at the bottom', async () => {
-    element.group = createContextGroup({offset: 30, count: 20});
-    element.showConfig = 'above';
-
-    await waitEventLoop();
-
-    const buttons = element.shadowRoot!.querySelectorAll(
-      'paper-button.showContext'
-    );
-
-    assert.equal(buttons.length, 2);
-    assert.equal(buttons[0].textContent!.trim(), '+20 common lines');
-    assert.equal(buttons[1].textContent!.trim(), '+10');
-
-    assert.include([...buttons[0].classList.values()], 'aboveButton');
-    assert.include([...buttons[1].classList.values()], 'aboveButton');
-  });
-
-  function prepareForBlockExpansion(syntaxTree: SyntaxBlock[]) {
-    element.renderPreferences!.use_block_expansion = true;
-    element.diff!.meta_b = {
-      syntax_tree: syntaxTree,
-    } as any as DiffFileMetaInfo;
-  }
-
-  test('context control with block expansion at the top', async () => {
-    prepareForBlockExpansion([]);
-    element.group = createContextGroup({offset: 0, count: 20});
-    element.showConfig = 'below';
-
-    await waitEventLoop();
-
-    const fullExpansionButtons = element.shadowRoot!.querySelectorAll(
-      '.fullExpansion paper-button'
-    );
-    const partialExpansionButtons = element.shadowRoot!.querySelectorAll(
-      '.partialExpansion paper-button'
-    );
-    const blockExpansionButtons = element.shadowRoot!.querySelectorAll(
-      '.blockExpansion paper-button'
-    );
-    assert.equal(fullExpansionButtons.length, 1);
-    assert.equal(partialExpansionButtons.length, 1);
-    assert.equal(blockExpansionButtons.length, 1);
-    assert.equal(
-      blockExpansionButtons[0].querySelector('span')!.textContent!.trim(),
-      '+Block'
-    );
-    assert.include(
-      [...blockExpansionButtons[0].classList.values()],
-      'belowButton'
-    );
-  });
-
-  test('context control with block expansion in the middle', async () => {
-    prepareForBlockExpansion([]);
-    element.group = createContextGroup({offset: 10, count: 20});
-    element.showConfig = 'both';
-
-    await waitEventLoop();
-
-    const fullExpansionButtons = element.shadowRoot!.querySelectorAll(
-      '.fullExpansion paper-button'
-    );
-    const partialExpansionButtons = element.shadowRoot!.querySelectorAll(
-      '.partialExpansion paper-button'
-    );
-    const blockExpansionButtons = element.shadowRoot!.querySelectorAll(
-      '.blockExpansion paper-button'
-    );
-    assert.equal(fullExpansionButtons.length, 1);
-    assert.equal(partialExpansionButtons.length, 2);
-    assert.equal(blockExpansionButtons.length, 2);
-    assert.equal(
-      blockExpansionButtons[0].querySelector('span')!.textContent!.trim(),
-      '+Block'
-    );
-    assert.equal(
-      blockExpansionButtons[1].querySelector('span')!.textContent!.trim(),
-      '+Block'
-    );
-    assert.include(
-      [...blockExpansionButtons[0].classList.values()],
-      'aboveButton'
-    );
-    assert.include(
-      [...blockExpansionButtons[1].classList.values()],
-      'belowButton'
-    );
-  });
-
-  test('context control with block expansion at the bottom', async () => {
-    prepareForBlockExpansion([]);
-    element.group = createContextGroup({offset: 30, count: 20});
-    element.showConfig = 'above';
-
-    await waitEventLoop();
-
-    const fullExpansionButtons = element.shadowRoot!.querySelectorAll(
-      '.fullExpansion paper-button'
-    );
-    const partialExpansionButtons = element.shadowRoot!.querySelectorAll(
-      '.partialExpansion paper-button'
-    );
-    const blockExpansionButtons = element.shadowRoot!.querySelectorAll(
-      '.blockExpansion paper-button'
-    );
-    assert.equal(fullExpansionButtons.length, 1);
-    assert.equal(partialExpansionButtons.length, 1);
-    assert.equal(blockExpansionButtons.length, 1);
-    assert.equal(
-      blockExpansionButtons[0].querySelector('span')!.textContent!.trim(),
-      '+Block'
-    );
-    assert.include(
-      [...blockExpansionButtons[0].classList.values()],
-      'aboveButton'
-    );
-  });
-
-  test('+ Block tooltip tooltip shows syntax block containing the target lines above and below', async () => {
-    prepareForBlockExpansion([
-      {
-        name: 'aSpecificFunction',
-        range: {start_line: 1, start_column: 0, end_line: 25, end_column: 0},
-        children: [],
-      },
-      {
-        name: 'anotherFunction',
-        range: {start_line: 26, start_column: 0, end_line: 50, end_column: 0},
-        children: [],
-      },
-    ]);
-    element.group = createContextGroup({offset: 10, count: 20});
-    element.showConfig = 'both';
-
-    await waitEventLoop();
-
-    const blockExpansionButtons = element.shadowRoot!.querySelectorAll(
-      '.blockExpansion paper-button'
-    );
-    assert.equal(
-      blockExpansionButtons[0]
-        .querySelector('.breadcrumbTooltip')!
-        .textContent?.trim(),
-      'aSpecificFunction'
-    );
-    assert.equal(
-      blockExpansionButtons[1]
-        .querySelector('.breadcrumbTooltip')!
-        .textContent?.trim(),
-      'anotherFunction'
-    );
-  });
-
-  test('+Block tooltip shows nested syntax blocks as breadcrumbs', async () => {
-    prepareForBlockExpansion([
-      {
-        name: 'aSpecificNamespace',
-        range: {start_line: 1, start_column: 0, end_line: 200, end_column: 0},
-        children: [
-          {
-            name: 'MyClass',
-            range: {
-              start_line: 2,
-              start_column: 0,
-              end_line: 100,
-              end_column: 0,
-            },
-            children: [
-              {
-                name: 'aMethod',
-                range: {
-                  start_line: 5,
-                  start_column: 0,
-                  end_line: 80,
-                  end_column: 0,
-                },
-                children: [],
-              },
-            ],
-          },
-        ],
-      },
-    ]);
-    element.group = createContextGroup({offset: 10, count: 20});
-    element.showConfig = 'both';
-
-    await waitEventLoop();
-
-    const blockExpansionButtons = element.shadowRoot!.querySelectorAll(
-      '.blockExpansion paper-button'
-    );
-    assert.equal(
-      blockExpansionButtons[0]
-        .querySelector('.breadcrumbTooltip')!
-        .textContent?.trim(),
-      'aSpecificNamespace > MyClass > aMethod'
-    );
-  });
-
-  test('+Block tooltip shows (anonymous) for empty blocks', async () => {
-    prepareForBlockExpansion([
-      {
-        name: 'aSpecificNamespace',
-        range: {start_line: 1, start_column: 0, end_line: 200, end_column: 0},
-        children: [
-          {
-            name: '',
-            range: {
-              start_line: 2,
-              start_column: 0,
-              end_line: 100,
-              end_column: 0,
-            },
-            children: [
-              {
-                name: 'aMethod',
-                range: {
-                  start_line: 5,
-                  start_column: 0,
-                  end_line: 80,
-                  end_column: 0,
-                },
-                children: [],
-              },
-            ],
-          },
-        ],
-      },
-    ]);
-    element.group = createContextGroup({offset: 10, count: 20});
-    element.showConfig = 'both';
-    await waitEventLoop();
-
-    const blockExpansionButtons = element.shadowRoot!.querySelectorAll(
-      '.blockExpansion paper-button'
-    );
-    assert.equal(
-      blockExpansionButtons[0]
-        .querySelector('.breadcrumbTooltip')!
-        .textContent?.trim(),
-      'aSpecificNamespace > (anonymous) > aMethod'
-    );
-  });
-
-  test('+Block tooltip shows "all common lines" for empty syntax tree', async () => {
-    prepareForBlockExpansion([]);
-
-    element.group = createContextGroup({offset: 10, count: 20});
-    element.showConfig = 'both';
-    await waitEventLoop();
-
-    const blockExpansionButtons = element.shadowRoot!.querySelectorAll(
-      '.blockExpansion paper-button'
-    );
-    const tooltipAbove =
-      blockExpansionButtons[0].querySelector('paper-tooltip')!;
-    const tooltipBelow =
-      blockExpansionButtons[1].querySelector('paper-tooltip')!;
-    assert.equal(
-      tooltipAbove.querySelector('.breadcrumbTooltip')!.textContent?.trim(),
-      '20 common lines'
-    );
-    assert.equal(
-      tooltipBelow.querySelector('.breadcrumbTooltip')!.textContent?.trim(),
-      '20 common lines'
-    );
-    assert.equal(tooltipAbove.getAttribute('position'), 'top');
-    assert.equal(tooltipBelow.getAttribute('position'), 'bottom');
-  });
-});
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-builder-binary.ts b/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-builder-binary.ts
deleted file mode 100644
index 9467654..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-builder-binary.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * @license
- * Copyright 2017 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import {GrDiffBuilder} from './gr-diff-builder';
-import {DiffInfo, DiffPreferencesInfo} from '../../../types/diff';
-import {createElementDiff} from '../../diff/gr-diff/gr-diff-utils';
-import {GrDiffGroup} from '../gr-diff/gr-diff-group';
-import {html, render} from 'lit';
-import {FILE} from '../../../api/diff';
-
-export class GrDiffBuilderBinary extends GrDiffBuilder {
-  constructor(
-    diff: DiffInfo,
-    prefs: DiffPreferencesInfo,
-    outputEl: HTMLElement
-  ) {
-    super(diff, prefs, outputEl);
-  }
-
-  override buildSectionElement(group: GrDiffGroup): HTMLElement {
-    const section = createElementDiff('tbody', 'binary-diff');
-    // Do not create a diff row for LOST.
-    if (group.lines[0].beforeNumber !== FILE) return section;
-    return super.buildSectionElement(group);
-  }
-
-  public renderBinaryDiff() {
-    render(
-      html`
-        <tbody class="gr-diff binary-diff">
-          <tr class="gr-diff">
-            <td colspan="5" class="gr-diff">
-              <span>Difference in binary files</span>
-            </td>
-          </tr>
-        </tbody>
-      `,
-      this.outputEl
-    );
-  }
-}
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-builder-element.ts b/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-builder-element.ts
deleted file mode 100644
index 5a4a26d..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-builder-element.ts
+++ /dev/null
@@ -1,573 +0,0 @@
-/**
- * @license
- * Copyright 2016 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import '../gr-diff-processor/gr-diff-processor';
-import '../../../elements/shared/gr-hovercard/gr-hovercard';
-import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
-import {
-  GrDiffBuilder,
-  DiffContextExpandedEventDetail,
-  isImageDiffBuilder,
-  isBinaryDiffBuilder,
-} from './gr-diff-builder';
-import {GrDiffBuilderImage} from './gr-diff-builder-image';
-import {GrDiffBuilderBinary} from './gr-diff-builder-binary';
-import {BlameInfo, ImageInfo} from '../../../types/common';
-import {DiffInfo, DiffPreferencesInfo} from '../../../types/diff';
-import {CoverageRange, DiffLayer} from '../../../types/types';
-import {
-  GrDiffProcessor,
-  GroupConsumer,
-  KeyLocations,
-} from '../gr-diff-processor/gr-diff-processor';
-import {
-  CommentRangeLayer,
-  GrRangedCommentLayer,
-} from '../../diff/gr-ranged-comment-layer/gr-ranged-comment-layer';
-import {GrCoverageLayer} from '../../diff/gr-coverage-layer/gr-coverage-layer';
-import {DiffViewMode, LineNumber, RenderPreferences} from '../../../api/diff';
-import {createDefaultDiffPrefs, Side} from '../../../constants/constants';
-import {GrDiffLine} from '../gr-diff/gr-diff-line';
-import {
-  GrDiffGroup,
-  GrDiffGroupType,
-  hideInContextControl,
-} from '../gr-diff/gr-diff-group';
-import {getLineNumber, getSideByLineEl} from '../../diff/gr-diff/gr-diff-utils';
-import {fireAlert, fire} from '../../../utils/event-util';
-import {assertIsDefined} from '../../../utils/common-util';
-import {isImageDiff} from '../../../utils/diff-util';
-
-const TRAILING_WHITESPACE_PATTERN = /\s+$/;
-const COMMIT_MSG_PATH = '/COMMIT_MSG';
-const COMMIT_MSG_LINE_LENGTH = 72;
-
-declare global {
-  interface HTMLElementEventMap {
-    /**
-     * Fired when the diff begins rendering - both for full renders and for
-     * partial rerenders.
-     */
-    'render-start': CustomEvent<{}>;
-    /**
-     * Fired when the diff finishes rendering text content - both for full
-     * renders and for partial rerenders.
-     */
-    'render-content': CustomEvent<{}>;
-  }
-}
-
-export function getLineNumberCellWidth(prefs: DiffPreferencesInfo) {
-  return prefs.font_size * 4;
-}
-
-function annotateSymbols(
-  contentEl: HTMLElement,
-  line: GrDiffLine,
-  separator: string | RegExp,
-  className: string
-) {
-  const split = line.text.split(separator);
-  if (!split || split.length < 2) {
-    return;
-  }
-  for (let i = 0, pos = 0; i < split.length - 1; i++) {
-    // Skip forward by the length of the content
-    pos += split[i].length;
-
-    GrAnnotation.annotateElement(contentEl, pos, 1, `gr-diff ${className}`);
-
-    pos++;
-  }
-}
-
-// TODO: Rename the class and the file and remove "element". This is not an
-// element anymore.
-export class GrDiffBuilderElement implements GroupConsumer {
-  diff?: DiffInfo;
-
-  diffElement?: HTMLTableElement;
-
-  viewMode?: string;
-
-  baseImage: ImageInfo | null = null;
-
-  revisionImage: ImageInfo | null = null;
-
-  path?: string;
-
-  prefs: DiffPreferencesInfo = createDefaultDiffPrefs();
-
-  renderPrefs?: RenderPreferences;
-
-  useNewImageDiffUi = false;
-
-  /**
-   * Layers passed in from the outside.
-   *
-   * See `layersInternal` for where these layers will end up together with the
-   * internal layers.
-   */
-  layers: DiffLayer[] = [];
-
-  // visible for testing
-  builder?: GrDiffBuilder;
-
-  /**
-   * All layers, both from the outside and the default ones. See `layers` for
-   * the property that can be set from the outside.
-   */
-  // visible for testing
-  layersInternal: DiffLayer[] = [];
-
-  // visible for testing
-  showTabs?: boolean;
-
-  // visible for testing
-  showTrailingWhitespace?: boolean;
-
-  private coverageLayerLeft = new GrCoverageLayer(Side.LEFT);
-
-  private coverageLayerRight = new GrCoverageLayer(Side.RIGHT);
-
-  private rangeLayer?: GrRangedCommentLayer;
-
-  // visible for testing
-  processor?: GrDiffProcessor;
-
-  /**
-   * Groups are mostly just passed on to the diff builder (this.builder). But
-   * we also keep track of them here for being able to fire a `render-content`
-   * event when .element of each group has rendered.
-   *
-   * TODO: Refactor DiffBuilderElement and DiffBuilders with a cleaner
-   * separation of responsibilities.
-   */
-  private groups: GrDiffGroup[] = [];
-
-  updateCommentRanges(ranges: CommentRangeLayer[]) {
-    this.rangeLayer?.updateRanges(ranges);
-  }
-
-  updateCoverageRanges(rs: CoverageRange[]) {
-    this.coverageLayerLeft.setRanges(rs.filter(r => r?.side === Side.LEFT));
-    this.coverageLayerRight.setRanges(rs.filter(r => r?.side === Side.RIGHT));
-  }
-
-  render(keyLocations: KeyLocations): Promise<void> {
-    assertIsDefined(this.diff, 'diff');
-    assertIsDefined(this.diffElement, 'diff table');
-
-    // Setting up annotation layers must happen after plugins are
-    // installed, and |render| satisfies the requirement, however,
-    // |attached| doesn't because in the diff view page, the element is
-    // attached before plugins are installed.
-    this.setupAnnotationLayers();
-
-    this.showTabs = this.prefs.show_tabs;
-    this.showTrailingWhitespace = this.prefs.show_whitespace_errors;
-
-    this.cleanup();
-    this.builder = this.getDiffBuilder();
-    this.init();
-
-    // TODO: Just pass along the diff model here instead of setting many
-    // individual properties.
-    this.processor = new GrDiffProcessor();
-    this.processor.consumer = this;
-    this.processor.context = this.prefs.context;
-    this.processor.keyLocations = keyLocations;
-    if (this.renderPrefs?.num_lines_rendered_at_once) {
-      this.processor.asyncThreshold =
-        this.renderPrefs.num_lines_rendered_at_once;
-    }
-
-    this.clearDiffContent();
-    this.builder.addColumns(
-      this.diffElement,
-      getLineNumberCellWidth(this.prefs)
-    );
-
-    const isBinary = !!(isImageDiff(this.diff) || this.diff.binary);
-
-    fire(this.diffElement, 'render-start', {});
-    return (
-      this.processor
-        .process(this.diff.content, isBinary)
-        .then(async () => {
-          if (isImageDiffBuilder(this.builder)) {
-            this.builder.renderImageDiff();
-          } else if (isBinaryDiffBuilder(this.builder)) {
-            this.builder.renderBinaryDiff();
-          }
-          await this.untilGroupsRendered();
-          fire(this.diffElement, 'render-content', {});
-        })
-        // Mocha testing does not like uncaught rejections, so we catch
-        // the cancels which are expected and should not throw errors in
-        // tests.
-        .catch(e => {
-          if (!e.isCanceled) return Promise.reject(e);
-          return;
-        })
-    );
-  }
-
-  // visible for testing
-  async untilGroupsRendered(groups: readonly GrDiffGroup[] = this.groups) {
-    return Promise.all(groups.map(g => g.waitUntilRendered()));
-  }
-
-  private onDiffContextExpanded = (
-    e: CustomEvent<DiffContextExpandedEventDetail>
-  ) => {
-    // Don't stop propagation. The host may listen for reporting or
-    // resizing.
-    this.replaceGroup(e.detail.contextGroup, e.detail.groups);
-  };
-
-  // visible for testing
-  setupAnnotationLayers() {
-    this.rangeLayer = new GrRangedCommentLayer();
-
-    const layers: DiffLayer[] = [
-      this.createTrailingWhitespaceLayer(),
-      this.createIntralineLayer(),
-      this.createTabIndicatorLayer(),
-      this.createSpecialCharacterIndicatorLayer(),
-      this.rangeLayer,
-      this.coverageLayerLeft,
-      this.coverageLayerRight,
-    ];
-
-    if (this.layers) {
-      layers.push(...this.layers);
-    }
-    this.layersInternal = layers;
-  }
-
-  getContentTdByLine(lineNumber: LineNumber, side?: Side) {
-    if (!this.builder) return undefined;
-    return this.builder.getContentTdByLine(lineNumber, side);
-  }
-
-  getContentTdByLineEl(lineEl?: Element): Element | undefined {
-    if (!lineEl) return undefined;
-    const line = getLineNumber(lineEl);
-    if (!line) return undefined;
-    const side = getSideByLineEl(lineEl);
-    return this.getContentTdByLine(line, side);
-  }
-
-  getLineElByNumber(lineNumber: LineNumber, side?: Side) {
-    if (!this.builder) return undefined;
-    return this.builder.getLineElByNumber(lineNumber, side);
-  }
-
-  getLineNumberRows() {
-    if (!this.builder) return [];
-    return this.builder.getLineNumberRows();
-  }
-
-  getLineNumEls(side: Side) {
-    if (!this.builder) return [];
-    return this.builder.getLineNumEls(side);
-  }
-
-  /**
-   * When the line is hidden behind a context expander, expand it.
-   *
-   * @param lineNum A line number to expand. Using number here because other
-   *   special case line numbers are never hidden, so it does not make sense
-   *   to expand them.
-   * @param side The side the line number refer to.
-   */
-  unhideLine(lineNum: number, side: Side) {
-    if (!this.builder) return;
-    const group = this.builder.findGroup(side, lineNum);
-    // Cannot unhide a line that is not part of the diff.
-    if (!group) return;
-    // If it's already visible, great!
-    if (group.type !== GrDiffGroupType.CONTEXT_CONTROL) return;
-    const lineRange = group.lineRange[side];
-    const lineOffset = lineNum - lineRange.start_line;
-    const newGroups = [];
-    const groups = hideInContextControl(
-      group.contextGroups,
-      0,
-      lineOffset - 1 - this.prefs.context
-    );
-    // If there is a context group, it will be the first group because we
-    // start hiding from 0 offset
-    if (groups[0].type === GrDiffGroupType.CONTEXT_CONTROL) {
-      newGroups.push(groups.shift()!);
-    }
-    newGroups.push(
-      ...hideInContextControl(
-        groups,
-        lineOffset + 1 + this.prefs.context,
-        // Both ends inclusive, so difference is the offset of the last line.
-        // But we need to pass the first line not to hide, which is the element
-        // after.
-        lineRange.end_line - lineRange.start_line + 1
-      )
-    );
-    this.replaceGroup(group, newGroups);
-  }
-
-  /**
-   * Replace the group of a context control section by rendering the provided
-   * groups instead. This happens in response to expanding a context control
-   * group.
-   *
-   * @param contextGroup The context control group to replace
-   * @param newGroups The groups that are replacing the context control group
-   */
-  private replaceGroup(
-    contextGroup: GrDiffGroup,
-    newGroups: readonly GrDiffGroup[]
-  ) {
-    if (!this.builder) return;
-    fire(this.diffElement, 'render-start', {});
-    this.builder.replaceGroup(contextGroup, newGroups);
-    this.groups = this.groups.filter(g => g !== contextGroup);
-    this.groups.push(...newGroups);
-    this.untilGroupsRendered(newGroups).then(() => {
-      fire(this.diffElement, 'render-content', {});
-    });
-  }
-
-  /**
-   * This is meant to be called when the gr-diff component re-connects, or when
-   * the diff is (re-)rendered.
-   *
-   * Make sure that this method is symmetric with cleanup(), which is called
-   * when gr-diff disconnects.
-   */
-  init() {
-    this.cleanup();
-    this.diffElement?.addEventListener(
-      'diff-context-expanded-internal',
-      this.onDiffContextExpanded
-    );
-    this.builder?.init();
-  }
-
-  /**
-   * This is meant to be called when the gr-diff component disconnects, or when
-   * the diff is (re-)rendered.
-   *
-   * Make sure that this method is symmetric with init(), which is called when
-   * gr-diff re-connects.
-   */
-  cleanup() {
-    this.processor?.cancel();
-    this.builder?.cleanup();
-    this.diffElement?.removeEventListener(
-      'diff-context-expanded-internal',
-      this.onDiffContextExpanded
-    );
-  }
-
-  // visible for testing
-  handlePreferenceError(pref: string): never {
-    const message =
-      `The value of the '${pref}' user preference is ` +
-      'invalid. Fix in diff preferences';
-    assertIsDefined(this.diffElement, 'diff table');
-    fireAlert(this.diffElement, message);
-    throw Error(`Invalid preference value: ${pref}`);
-  }
-
-  // visible for testing
-  getDiffBuilder(): GrDiffBuilder {
-    assertIsDefined(this.diff, 'diff');
-    assertIsDefined(this.diffElement, 'diff table');
-    if (isNaN(this.prefs.tab_size) || this.prefs.tab_size <= 0) {
-      this.handlePreferenceError('tab size');
-    }
-
-    if (isNaN(this.prefs.line_length) || this.prefs.line_length <= 0) {
-      this.handlePreferenceError('diff width');
-    }
-
-    const localPrefs = {...this.prefs};
-    if (this.path === COMMIT_MSG_PATH) {
-      // override line_length for commit msg the same way as
-      // in gr-diff
-      localPrefs.line_length = COMMIT_MSG_LINE_LENGTH;
-    }
-
-    let builder = null;
-    if (isImageDiff(this.diff)) {
-      builder = new GrDiffBuilderImage(
-        this.diff,
-        localPrefs,
-        this.diffElement,
-        this.baseImage,
-        this.revisionImage,
-        this.renderPrefs,
-        this.useNewImageDiffUi
-      );
-    } else if (this.diff.binary) {
-      return new GrDiffBuilderBinary(this.diff, localPrefs, this.diffElement);
-    } else if (this.viewMode === DiffViewMode.SIDE_BY_SIDE) {
-      this.renderPrefs = {
-        ...this.renderPrefs,
-        view_mode: DiffViewMode.SIDE_BY_SIDE,
-      };
-      builder = new GrDiffBuilder(
-        this.diff,
-        localPrefs,
-        this.diffElement,
-        this.layersInternal,
-        this.renderPrefs
-      );
-    } else if (this.viewMode === DiffViewMode.UNIFIED) {
-      this.renderPrefs = {
-        ...this.renderPrefs,
-        view_mode: DiffViewMode.UNIFIED,
-      };
-      builder = new GrDiffBuilder(
-        this.diff,
-        localPrefs,
-        this.diffElement,
-        this.layersInternal,
-        this.renderPrefs
-      );
-    }
-    if (!builder) {
-      throw Error(`Unsupported diff view mode: ${this.viewMode}`);
-    }
-    return builder;
-  }
-
-  private clearDiffContent() {
-    assertIsDefined(this.diffElement, 'diff table');
-    this.diffElement.innerHTML = '';
-  }
-
-  /**
-   * Called when the processor starts converting the diff information from the
-   * server into chunks.
-   */
-  clearGroups() {
-    if (!this.builder) return;
-    this.groups = [];
-    this.builder.clearGroups();
-  }
-
-  /**
-   * Called when the processor is done converting a chunk of the diff.
-   */
-  addGroup(group: GrDiffGroup) {
-    if (!this.builder) return;
-    this.builder.addGroups([group]);
-    this.groups.push(group);
-  }
-
-  // visible for testing
-  createIntralineLayer(): DiffLayer {
-    return {
-      // Take a DIV.contentText element and a line object with intraline
-      // differences to highlight and apply them to the element as
-      // annotations.
-      annotate(contentEl: HTMLElement, _: HTMLElement, line: GrDiffLine) {
-        const HL_CLASS = 'gr-diff intraline';
-        for (const highlight of line.highlights) {
-          // The start and end indices could be the same if a highlight is
-          // meant to start at the end of a line and continue onto the
-          // next one. Ignore it.
-          if (highlight.startIndex === highlight.endIndex) {
-            continue;
-          }
-
-          // If endIndex isn't present, continue to the end of the line.
-          const endIndex =
-            highlight.endIndex === undefined
-              ? GrAnnotation.getStringLength(line.text)
-              : highlight.endIndex;
-
-          GrAnnotation.annotateElement(
-            contentEl,
-            highlight.startIndex,
-            endIndex - highlight.startIndex,
-            HL_CLASS
-          );
-        }
-      },
-    };
-  }
-
-  // visible for testing
-  createTabIndicatorLayer(): DiffLayer {
-    const show = () => this.showTabs;
-    return {
-      annotate(contentEl: HTMLElement, _: HTMLElement, line: GrDiffLine) {
-        // If visible tabs are disabled, do nothing.
-        if (!show()) {
-          return;
-        }
-
-        // Find and annotate the locations of tabs.
-        annotateSymbols(contentEl, line, '\t', 'tab-indicator');
-      },
-    };
-  }
-
-  private createSpecialCharacterIndicatorLayer(): DiffLayer {
-    return {
-      annotate(contentEl: HTMLElement, _: HTMLElement, line: GrDiffLine) {
-        // Find and annotate the locations of soft hyphen (\u00AD)
-        annotateSymbols(contentEl, line, '\u00AD', 'special-char-indicator');
-        // Find and annotate Stateful Unicode directional controls
-        annotateSymbols(
-          contentEl,
-          line,
-          /[\u202A-\u202E\u2066-\u2069]/,
-          'special-char-warning'
-        );
-      },
-    };
-  }
-
-  // visible for testing
-  createTrailingWhitespaceLayer(): DiffLayer {
-    const show = () => this.showTrailingWhitespace;
-
-    return {
-      annotate(contentEl: HTMLElement, _: HTMLElement, line: GrDiffLine) {
-        if (!show()) {
-          return;
-        }
-
-        const match = line.text.match(TRAILING_WHITESPACE_PATTERN);
-        if (match) {
-          // Normalize string positions in case there is unicode before or
-          // within the match.
-          const index = GrAnnotation.getStringLength(
-            line.text.substr(0, match.index)
-          );
-          const length = GrAnnotation.getStringLength(match[0]);
-          GrAnnotation.annotateElement(
-            contentEl,
-            index,
-            length,
-            'gr-diff trailing-whitespace'
-          );
-        }
-      },
-    };
-  }
-
-  setBlame(blame: BlameInfo[] | null) {
-    if (!this.builder) return;
-    this.builder.setBlame(blame ?? []);
-  }
-
-  updateRenderPrefs(renderPrefs: RenderPreferences) {
-    this.builder?.updateRenderPrefs(renderPrefs);
-  }
-}
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-builder-element_test.ts b/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-builder-element_test.ts
deleted file mode 100644
index 2cee232..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-builder-element_test.ts
+++ /dev/null
@@ -1,630 +0,0 @@
-/**
- * @license
- * Copyright 2016 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import '../../../test/common-test-setup';
-import {
-  createConfig,
-  createEmptyDiff,
-} from '../../../test/test-data-generators';
-import './gr-diff-builder-element';
-import {stubBaseUrl, waitUntil} from '../../../test/test-utils';
-import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
-import {GrDiffLine} from '../gr-diff/gr-diff-line';
-import {
-  DiffContent,
-  DiffLayer,
-  DiffPreferencesInfo,
-  DiffViewMode,
-  GrDiffLineType,
-  Side,
-} from '../../../api/diff';
-import {stubRestApi} from '../../../test/test-utils';
-import {waitForEventOnce} from '../../../utils/event-util';
-import {GrDiffBuilderElement} from './gr-diff-builder-element';
-import {createDefaultDiffPrefs} from '../../../constants/constants';
-import {KeyLocations} from '../gr-diff-processor/gr-diff-processor';
-import {fixture, html, assert} from '@open-wc/testing';
-import {GrDiffRow} from './gr-diff-row';
-import {GrDiffBuilder} from './gr-diff-builder';
-import {querySelectorAll} from '../../../utils/dom-util';
-
-const DEFAULT_PREFS = createDefaultDiffPrefs();
-
-suite('gr-diff-builder tests', () => {
-  let element: GrDiffBuilderElement;
-  let builder: GrDiffBuilder;
-  let diffTable: HTMLTableElement;
-
-  const setBuilderPrefs = (prefs: Partial<DiffPreferencesInfo>) => {
-    builder = new GrDiffBuilder(
-      createEmptyDiff(),
-      {...createDefaultDiffPrefs(), ...prefs},
-      diffTable
-    );
-  };
-
-  const line = (text: string) => {
-    const line = new GrDiffLine(GrDiffLineType.BOTH);
-    line.text = text;
-    return line;
-  };
-
-  setup(async () => {
-    diffTable = await fixture(html`<table id="diffTable"></table>`);
-    element = new GrDiffBuilderElement();
-    element.diffElement = diffTable;
-    stubRestApi('getLoggedIn').returns(Promise.resolve(false));
-    stubRestApi('getProjectConfig').returns(Promise.resolve(createConfig()));
-    stubBaseUrl('/r');
-    setBuilderPrefs({});
-  });
-
-  [DiffViewMode.UNIFIED, DiffViewMode.SIDE_BY_SIDE].forEach(mode => {
-    test(`line_length used for regular files under ${mode}`, () => {
-      element.path = '/a.txt';
-      element.viewMode = mode;
-      element.diff = createEmptyDiff();
-      element.prefs = {
-        ...createDefaultDiffPrefs(),
-        tab_size: 4,
-        line_length: 50,
-      };
-      builder = element.getDiffBuilder();
-      assert.equal(builder.prefs.line_length, 50);
-    });
-
-    test(`line_length ignored for commit msg under ${mode}`, () => {
-      element.path = '/COMMIT_MSG';
-      element.viewMode = mode;
-      element.diff = createEmptyDiff();
-      element.prefs = {
-        ...createDefaultDiffPrefs(),
-        tab_size: 4,
-        line_length: 50,
-      };
-      builder = element.getDiffBuilder();
-      assert.equal(builder.prefs.line_length, 72);
-    });
-  });
-
-  test('_handlePreferenceError throws with invalid preference', () => {
-    element.prefs = {...createDefaultDiffPrefs(), tab_size: 0};
-    assert.throws(() => element.getDiffBuilder());
-  });
-
-  test('_handlePreferenceError triggers alert and javascript error', () => {
-    const errorStub = sinon.stub();
-    diffTable.addEventListener('show-alert', errorStub);
-    assert.throws(() => element.handlePreferenceError('tab size'));
-    assert.equal(
-      errorStub.lastCall.args[0].detail.message,
-      "The value of the 'tab size' user preference is invalid. " +
-        'Fix in diff preferences'
-    );
-  });
-
-  suite('intraline differences', () => {
-    let el: HTMLElement;
-    let str: string;
-    let annotateElementSpy: sinon.SinonSpy;
-    let layer: DiffLayer;
-    const lineNumberEl = document.createElement('td');
-
-    function slice(str: string, start: number, end?: number) {
-      return Array.from(str).slice(start, end).join('');
-    }
-
-    setup(async () => {
-      el = await fixture(html`
-        <div>Lorem ipsum dolor sit amet, suspendisse inceptos vehicula</div>
-      `);
-      str = el.textContent ?? '';
-      annotateElementSpy = sinon.spy(GrAnnotation, 'annotateElement');
-      layer = element.createIntralineLayer();
-    });
-
-    test('annotate no highlights', () => {
-      layer.annotate(el, lineNumberEl, line(str), Side.LEFT);
-
-      // The content is unchanged.
-      assert.isFalse(annotateElementSpy.called);
-      assert.equal(el.childNodes.length, 1);
-      assert.instanceOf(el.childNodes[0], Text);
-      assert.equal(str, el.childNodes[0].textContent);
-    });
-
-    test('annotate with highlights', () => {
-      const l = line(str);
-      l.highlights = [
-        {contentIndex: 0, startIndex: 6, endIndex: 12},
-        {contentIndex: 0, startIndex: 18, endIndex: 22},
-      ];
-      const str0 = slice(str, 0, 6);
-      const str1 = slice(str, 6, 12);
-      const str2 = slice(str, 12, 18);
-      const str3 = slice(str, 18, 22);
-      const str4 = slice(str, 22);
-
-      layer.annotate(el, lineNumberEl, l, Side.LEFT);
-
-      assert.isTrue(annotateElementSpy.called);
-      assert.equal(el.childNodes.length, 5);
-
-      assert.instanceOf(el.childNodes[0], Text);
-      assert.equal(el.childNodes[0].textContent, str0);
-
-      assert.notInstanceOf(el.childNodes[1], Text);
-      assert.equal(el.childNodes[1].textContent, str1);
-
-      assert.instanceOf(el.childNodes[2], Text);
-      assert.equal(el.childNodes[2].textContent, str2);
-
-      assert.notInstanceOf(el.childNodes[3], Text);
-      assert.equal(el.childNodes[3].textContent, str3);
-
-      assert.instanceOf(el.childNodes[4], Text);
-      assert.equal(el.childNodes[4].textContent, str4);
-    });
-
-    test('annotate without endIndex', () => {
-      const l = line(str);
-      l.highlights = [{contentIndex: 0, startIndex: 28}];
-
-      const str0 = slice(str, 0, 28);
-      const str1 = slice(str, 28);
-
-      layer.annotate(el, lineNumberEl, l, Side.LEFT);
-
-      assert.isTrue(annotateElementSpy.called);
-      assert.equal(el.childNodes.length, 2);
-
-      assert.instanceOf(el.childNodes[0], Text);
-      assert.equal(el.childNodes[0].textContent, str0);
-
-      assert.notInstanceOf(el.childNodes[1], Text);
-      assert.equal(el.childNodes[1].textContent, str1);
-    });
-
-    test('annotate ignores empty highlights', () => {
-      const l = line(str);
-      l.highlights = [{contentIndex: 0, startIndex: 28, endIndex: 28}];
-
-      layer.annotate(el, lineNumberEl, l, Side.LEFT);
-
-      assert.isFalse(annotateElementSpy.called);
-      assert.equal(el.childNodes.length, 1);
-    });
-
-    test('annotate handles unicode', () => {
-      // Put some unicode into the string:
-      str = str.replace(/\s/g, '💢');
-      el.textContent = str;
-      const l = line(str);
-      l.highlights = [{contentIndex: 0, startIndex: 6, endIndex: 12}];
-
-      const str0 = slice(str, 0, 6);
-      const str1 = slice(str, 6, 12);
-      const str2 = slice(str, 12);
-
-      layer.annotate(el, lineNumberEl, l, Side.LEFT);
-
-      assert.isTrue(annotateElementSpy.called);
-      assert.equal(el.childNodes.length, 3);
-
-      assert.instanceOf(el.childNodes[0], Text);
-      assert.equal(el.childNodes[0].textContent, str0);
-
-      assert.notInstanceOf(el.childNodes[1], Text);
-      assert.equal(el.childNodes[1].textContent, str1);
-
-      assert.instanceOf(el.childNodes[2], Text);
-      assert.equal(el.childNodes[2].textContent, str2);
-    });
-
-    test('annotate handles unicode w/o endIndex', () => {
-      // Put some unicode into the string:
-      str = str.replace(/\s/g, '💢');
-      el.textContent = str;
-
-      const l = line(str);
-      l.highlights = [{contentIndex: 0, startIndex: 6}];
-
-      const str0 = slice(str, 0, 6);
-      const str1 = slice(str, 6);
-      const numHighlightedChars = GrAnnotation.getStringLength(str1);
-
-      layer.annotate(el, lineNumberEl, l, Side.LEFT);
-
-      assert.isTrue(annotateElementSpy.calledWith(el, 6, numHighlightedChars));
-      assert.equal(el.childNodes.length, 2);
-
-      assert.instanceOf(el.childNodes[0], Text);
-      assert.equal(el.childNodes[0].textContent, str0);
-
-      assert.notInstanceOf(el.childNodes[1], Text);
-      assert.equal(el.childNodes[1].textContent, str1);
-    });
-  });
-
-  suite('tab indicators', () => {
-    let layer: DiffLayer;
-    const lineNumberEl = document.createElement('td');
-
-    setup(() => {
-      element.showTabs = true;
-      layer = element.createTabIndicatorLayer();
-    });
-
-    test('does nothing with empty line', () => {
-      const l = line('');
-      const el = document.createElement('div');
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
-
-      layer.annotate(el, lineNumberEl, l, Side.LEFT);
-
-      assert.isFalse(annotateElementStub.called);
-    });
-
-    test('does nothing with no tabs', () => {
-      const str = 'lorem ipsum no tabs';
-      const l = line(str);
-      const el = document.createElement('div');
-      el.textContent = str;
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
-
-      layer.annotate(el, lineNumberEl, l, Side.LEFT);
-
-      assert.isFalse(annotateElementStub.called);
-    });
-
-    test('annotates tab at beginning', () => {
-      const str = '\tlorem upsum';
-      const l = line(str);
-      const el = document.createElement('div');
-      el.textContent = str;
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
-
-      layer.annotate(el, lineNumberEl, l, Side.LEFT);
-
-      assert.equal(annotateElementStub.callCount, 1);
-      const args = annotateElementStub.getCalls()[0].args;
-      assert.equal(args[0], el);
-      assert.equal(args[1], 0, 'offset of tab indicator');
-      assert.equal(args[2], 1, 'length of tab indicator');
-      assert.include(args[3], 'tab-indicator');
-    });
-
-    test('does not annotate when disabled', () => {
-      element.showTabs = false;
-
-      const str = '\tlorem upsum';
-      const l = line(str);
-      const el = document.createElement('div');
-      el.textContent = str;
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
-
-      layer.annotate(el, lineNumberEl, l, Side.LEFT);
-
-      assert.isFalse(annotateElementStub.called);
-    });
-
-    test('annotates multiple in beginning', () => {
-      const str = '\t\tlorem upsum';
-      const l = line(str);
-      const el = document.createElement('div');
-      el.textContent = str;
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
-
-      layer.annotate(el, lineNumberEl, l, Side.LEFT);
-
-      assert.equal(annotateElementStub.callCount, 2);
-
-      let args = annotateElementStub.getCalls()[0].args;
-      assert.equal(args[0], el);
-      assert.equal(args[1], 0, 'offset of tab indicator');
-      assert.equal(args[2], 1, 'length of tab indicator');
-      assert.include(args[3], 'tab-indicator');
-
-      args = annotateElementStub.getCalls()[1].args;
-      assert.equal(args[0], el);
-      assert.equal(args[1], 1, 'offset of tab indicator');
-      assert.equal(args[2], 1, 'length of tab indicator');
-      assert.include(args[3], 'tab-indicator');
-    });
-
-    test('annotates intermediate tabs', () => {
-      const str = 'lorem\tupsum';
-      const l = line(str);
-      const el = document.createElement('div');
-      el.textContent = str;
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
-
-      layer.annotate(el, lineNumberEl, l, Side.LEFT);
-
-      assert.equal(annotateElementStub.callCount, 1);
-      const args = annotateElementStub.getCalls()[0].args;
-      assert.equal(args[0], el);
-      assert.equal(args[1], 5, 'offset of tab indicator');
-      assert.equal(args[2], 1, 'length of tab indicator');
-      assert.include(args[3], 'tab-indicator');
-    });
-  });
-
-  suite('layers', () => {
-    let initialLayersCount = 0;
-    let withLayerCount = 0;
-    setup(() => {
-      const layers: DiffLayer[] = [];
-      element.layers = layers;
-      element.showTrailingWhitespace = true;
-      element.setupAnnotationLayers();
-      initialLayersCount = element.layersInternal.length;
-    });
-
-    test('no layers', () => {
-      element.setupAnnotationLayers();
-      assert.equal(element.layersInternal.length, initialLayersCount);
-    });
-
-    suite('with layers', () => {
-      const layers: DiffLayer[] = [{annotate: () => {}}, {annotate: () => {}}];
-      setup(() => {
-        element.layers = layers;
-        element.showTrailingWhitespace = true;
-        element.setupAnnotationLayers();
-        withLayerCount = element.layersInternal.length;
-      });
-      test('with layers', () => {
-        element.setupAnnotationLayers();
-        assert.equal(element.layersInternal.length, withLayerCount);
-        assert.equal(initialLayersCount + layers.length, withLayerCount);
-      });
-    });
-  });
-
-  suite('trailing whitespace', () => {
-    let layer: DiffLayer;
-    const lineNumberEl = document.createElement('td');
-
-    setup(() => {
-      element.showTrailingWhitespace = true;
-      layer = element.createTrailingWhitespaceLayer();
-    });
-
-    test('does nothing with empty line', () => {
-      const l = line('');
-      const el = document.createElement('div');
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
-      layer.annotate(el, lineNumberEl, l, Side.LEFT);
-      assert.isFalse(annotateElementStub.called);
-    });
-
-    test('does nothing with no trailing whitespace', () => {
-      const str = 'lorem ipsum blah blah';
-      const l = line(str);
-      const el = document.createElement('div');
-      el.textContent = str;
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
-      layer.annotate(el, lineNumberEl, l, Side.LEFT);
-      assert.isFalse(annotateElementStub.called);
-    });
-
-    test('annotates trailing spaces', () => {
-      const str = 'lorem ipsum   ';
-      const l = line(str);
-      const el = document.createElement('div');
-      el.textContent = str;
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
-      layer.annotate(el, lineNumberEl, l, Side.LEFT);
-      assert.isTrue(annotateElementStub.called);
-      assert.equal(annotateElementStub.lastCall.args[1], 11);
-      assert.equal(annotateElementStub.lastCall.args[2], 3);
-    });
-
-    test('annotates trailing tabs', () => {
-      const str = 'lorem ipsum\t\t\t';
-      const l = line(str);
-      const el = document.createElement('div');
-      el.textContent = str;
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
-      layer.annotate(el, lineNumberEl, l, Side.LEFT);
-      assert.isTrue(annotateElementStub.called);
-      assert.equal(annotateElementStub.lastCall.args[1], 11);
-      assert.equal(annotateElementStub.lastCall.args[2], 3);
-    });
-
-    test('annotates mixed trailing whitespace', () => {
-      const str = 'lorem ipsum\t \t';
-      const l = line(str);
-      const el = document.createElement('div');
-      el.textContent = str;
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
-      layer.annotate(el, lineNumberEl, l, Side.LEFT);
-      assert.isTrue(annotateElementStub.called);
-      assert.equal(annotateElementStub.lastCall.args[1], 11);
-      assert.equal(annotateElementStub.lastCall.args[2], 3);
-    });
-
-    test('unicode preceding trailing whitespace', () => {
-      const str = '💢\t';
-      const l = line(str);
-      const el = document.createElement('div');
-      el.textContent = str;
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
-      layer.annotate(el, lineNumberEl, l, Side.LEFT);
-      assert.isTrue(annotateElementStub.called);
-      assert.equal(annotateElementStub.lastCall.args[1], 1);
-      assert.equal(annotateElementStub.lastCall.args[2], 1);
-    });
-
-    test('does not annotate when disabled', () => {
-      element.showTrailingWhitespace = false;
-      const str = 'lorem upsum\t \t ';
-      const l = line(str);
-      const el = document.createElement('div');
-      el.textContent = str;
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
-      layer.annotate(el, lineNumberEl, l, Side.LEFT);
-      assert.isFalse(annotateElementStub.called);
-    });
-  });
-
-  suite('rendering text, images and binary files', () => {
-    let keyLocations: KeyLocations;
-    let content: DiffContent[] = [];
-
-    setup(() => {
-      element.viewMode = 'SIDE_BY_SIDE';
-      keyLocations = {left: {}, right: {}};
-      element.prefs = {
-        ...DEFAULT_PREFS,
-        context: -1,
-        syntax_highlighting: true,
-      };
-      content = [
-        {
-          a: ['all work and no play make andybons a dull boy'],
-          b: ['elgoog elgoog elgoog'],
-        },
-        {
-          ab: [
-            'Non eram nescius, Brute, cum, quae summis ingeniis ',
-            'exquisitaque doctrina philosophi Graeco sermone tractavissent',
-          ],
-        },
-      ];
-    });
-
-    test('text', async () => {
-      element.diff = {...createEmptyDiff(), content};
-      element.render(keyLocations);
-      await waitForEventOnce(diffTable, 'render-content');
-      assert.equal(querySelectorAll(diffTable, 'tbody')?.length, 4);
-    });
-
-    test('image', async () => {
-      const diff = {...createEmptyDiff(), content, binary: true};
-      diff.meta_a!.content_type = 'image/png';
-      diff.meta_b!.content_type = 'image/png';
-      element.diff = diff;
-      element.render(keyLocations);
-      await waitForEventOnce(diffTable, 'render-content');
-      assert.equal(querySelectorAll(diffTable, 'tbody')?.length, 4);
-    });
-
-    test('binary', async () => {
-      element.diff = {...createEmptyDiff(), content, binary: true};
-      element.render(keyLocations);
-      await waitForEventOnce(diffTable, 'render-content');
-      assert.equal(querySelectorAll(diffTable, 'tbody')?.length, 3);
-    });
-  });
-
-  suite('context hiding and expanding', () => {
-    let dispatchStub: sinon.SinonStub;
-
-    setup(async () => {
-      dispatchStub = sinon.stub(diffTable, 'dispatchEvent');
-      element.diff = {
-        ...createEmptyDiff(),
-        content: [
-          {ab: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(i => `unchanged ${i}`)},
-          {a: ['before'], b: ['after']},
-          {ab: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(i => `unchanged ${10 + i}`)},
-        ],
-      };
-      element.viewMode = DiffViewMode.SIDE_BY_SIDE;
-
-      const keyLocations: KeyLocations = {left: {}, right: {}};
-      element.prefs = {
-        ...DEFAULT_PREFS,
-        context: 1,
-      };
-      element.render(keyLocations);
-      // Make sure all listeners are installed.
-      await element.untilGroupsRendered();
-    });
-
-    test('hides lines behind two context controls', () => {
-      const contextControls = diffTable.querySelectorAll('gr-context-controls');
-      assert.equal(contextControls.length, 2);
-
-      const diffRows = diffTable.querySelectorAll('.diff-row');
-      // The first two are LOST and FILE line
-      assert.equal(diffRows.length, 2 + 1 + 1 + 1);
-      assert.include(diffRows[2].textContent, 'unchanged 10');
-      assert.include(diffRows[3].textContent, 'before');
-      assert.include(diffRows[3].textContent, 'after');
-      assert.include(diffRows[4].textContent, 'unchanged 11');
-    });
-
-    test('clicking +x common lines expands those lines', async () => {
-      const contextControls = diffTable.querySelectorAll('gr-context-controls');
-      const topExpandCommonButton =
-        contextControls[0].shadowRoot?.querySelectorAll<HTMLElement>(
-          '.showContext'
-        )[0];
-      assert.isOk(topExpandCommonButton);
-      assert.include(topExpandCommonButton!.textContent, '+9 common lines');
-      let diffRows = diffTable.querySelectorAll('.diff-row');
-      // 5 lines:
-      // FILE, LOST, the changed line plus one line of context in each direction
-      assert.equal(diffRows.length, 5);
-
-      topExpandCommonButton!.click();
-
-      await waitUntil(() => {
-        diffRows = diffTable.querySelectorAll<GrDiffRow>('.diff-row');
-        return diffRows.length === 14;
-      });
-      // 14 lines: The 5 above plus the 9 unchanged lines that were expanded
-      assert.equal(diffRows.length, 14);
-      assert.include(diffRows[2].textContent, 'unchanged 1');
-      assert.include(diffRows[3].textContent, 'unchanged 2');
-      assert.include(diffRows[4].textContent, 'unchanged 3');
-      assert.include(diffRows[5].textContent, 'unchanged 4');
-      assert.include(diffRows[6].textContent, 'unchanged 5');
-      assert.include(diffRows[7].textContent, 'unchanged 6');
-      assert.include(diffRows[8].textContent, 'unchanged 7');
-      assert.include(diffRows[9].textContent, 'unchanged 8');
-      assert.include(diffRows[10].textContent, 'unchanged 9');
-      assert.include(diffRows[11].textContent, 'unchanged 10');
-      assert.include(diffRows[12].textContent, 'before');
-      assert.include(diffRows[12].textContent, 'after');
-      assert.include(diffRows[13].textContent, 'unchanged 11');
-    });
-
-    test('unhideLine shows the line with context', async () => {
-      dispatchStub.reset();
-      element.unhideLine(4, Side.LEFT);
-
-      await waitUntil(() => {
-        const rows = diffTable.querySelectorAll<GrDiffRow>('.diff-row');
-        return rows.length === 2 + 5 + 1 + 1 + 1;
-      });
-
-      const diffRows = diffTable.querySelectorAll('.diff-row');
-      // The first two are LOST and FILE line
-      // Lines 3-5 (Line 4 plus 1 context in each direction) will be expanded
-      // Because context expanders do not hide <3 lines, lines 1-2 will also
-      // be shown.
-      // Lines 6-9 continue to be hidden
-      assert.equal(diffRows.length, 2 + 5 + 1 + 1 + 1);
-      assert.include(diffRows[2].textContent, 'unchanged 1');
-      assert.include(diffRows[3].textContent, 'unchanged 2');
-      assert.include(diffRows[4].textContent, 'unchanged 3');
-      assert.include(diffRows[5].textContent, 'unchanged 4');
-      assert.include(diffRows[6].textContent, 'unchanged 5');
-      assert.include(diffRows[7].textContent, 'unchanged 10');
-      assert.include(diffRows[8].textContent, 'before');
-      assert.include(diffRows[8].textContent, 'after');
-      assert.include(diffRows[9].textContent, 'unchanged 11');
-
-      await element.untilGroupsRendered();
-      const firedEventTypes = dispatchStub.getCalls().map(c => c.args[0].type);
-      assert.include(firedEventTypes, 'render-content');
-    });
-  });
-});
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-builder-image.ts b/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-builder-image.ts
deleted file mode 100644
index d71d52a..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-builder-image.ts
+++ /dev/null
@@ -1,279 +0,0 @@
-/**
- * @license
- * Copyright 2016 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import {ImageInfo} from '../../../types/common';
-import {DiffInfo, DiffPreferencesInfo} from '../../../types/diff';
-import {FILE, RenderPreferences, Side} from '../../../api/diff';
-import '../../diff/gr-diff-image-viewer/gr-image-viewer';
-import {html, LitElement, nothing} from 'lit';
-import {property, query, state} from 'lit/decorators.js';
-import {GrDiffBuilder} from './gr-diff-builder';
-import {createElementDiff, isNewDiff} from '../../diff/gr-diff/gr-diff-utils';
-import {GrDiffGroup} from '../gr-diff/gr-diff-group';
-
-// MIME types for images we allow showing. Do not include SVG, it can contain
-// arbitrary JavaScript.
-const IMAGE_MIME_PATTERN = /^image\/(bmp|gif|x-icon|jpeg|jpg|png|tiff|webp)$/;
-
-export class GrDiffBuilderImage extends GrDiffBuilder {
-  constructor(
-    diff: DiffInfo,
-    prefs: DiffPreferencesInfo,
-    outputEl: HTMLElement,
-    private readonly baseImage: ImageInfo | null,
-    private readonly revisionImage: ImageInfo | null,
-    renderPrefs?: RenderPreferences,
-    private readonly useNewImageDiffUi: boolean = false
-  ) {
-    super(diff, prefs, outputEl, [], renderPrefs);
-  }
-
-  override buildSectionElement(group: GrDiffGroup): HTMLElement {
-    const section = createElementDiff('tbody');
-    // Do not create a diff row for LOST.
-    if (group.lines[0].beforeNumber !== FILE) return section;
-    return super.buildSectionElement(group);
-  }
-
-  public renderImageDiff() {
-    const imageDiff = this.useNewImageDiffUi
-      ? this.createImageDiffNew()
-      : this.createImageDiffOld();
-    this.outputEl.appendChild(imageDiff);
-  }
-
-  private createImageDiffNew() {
-    const imageDiff = document.createElement(
-      'gr-diff-image-new'
-    ) as GrDiffImageNew;
-    imageDiff.automaticBlink = this.autoBlink();
-    imageDiff.baseImage = this.baseImage ?? undefined;
-    imageDiff.revisionImage = this.revisionImage ?? undefined;
-    return imageDiff;
-  }
-
-  private createImageDiffOld() {
-    const imageDiff = document.createElement(
-      'gr-diff-image-old'
-    ) as GrDiffImageOld;
-    imageDiff.baseImage = this.baseImage ?? undefined;
-    imageDiff.revisionImage = this.revisionImage ?? undefined;
-    return imageDiff;
-  }
-
-  private autoBlink(): boolean {
-    return !!this.renderPrefs?.image_diff_prefs?.automatic_blink;
-  }
-
-  override updateRenderPrefs(renderPrefs: RenderPreferences) {
-    this.renderPrefs = renderPrefs;
-
-    // We have to update `imageDiff.automaticBlink` manually, because `this` is
-    // not a LitElement.
-    const imageDiff = this.outputEl.querySelector(
-      'gr-diff-image-new'
-    ) as GrDiffImageNew;
-    if (imageDiff) imageDiff.automaticBlink = this.autoBlink();
-  }
-}
-
-class GrDiffImageNew extends LitElement {
-  @property() baseImage?: ImageInfo;
-
-  @property() revisionImage?: ImageInfo;
-
-  @property() automaticBlink = false;
-
-  /**
-   * The browser API for handling selection does not (yet) work for selection
-   * across multiple shadow DOM elements. So we are rendering gr-diff components
-   * into the light DOM instead of the shadow DOM by overriding this method,
-   * which was the recommended workaround by the lit team.
-   * See also https://github.com/WICG/webcomponents/issues/79.
-   */
-  override createRenderRoot() {
-    return this;
-  }
-
-  override render() {
-    return html`
-      <tbody class="gr-diff image-diff">
-        <tr class="gr-diff">
-          <td class="gr-diff" colspan="4">
-            <gr-image-viewer
-              class="gr-diff"
-              .baseUrl=${imageSrc(this.baseImage)}
-              .revisionUrl=${imageSrc(this.revisionImage)}
-              .automaticBlink=${this.automaticBlink}
-            >
-            </gr-image-viewer>
-          </td>
-        </tr>
-      </tbody>
-    `;
-  }
-}
-
-class GrDiffImageOld extends LitElement {
-  @property() baseImage?: ImageInfo;
-
-  @property() revisionImage?: ImageInfo;
-
-  @query('img.left') baseImageEl?: HTMLImageElement;
-
-  @query('img.right') revisionImageEl?: HTMLImageElement;
-
-  @state() baseError?: string;
-
-  @state() revisionError?: string;
-
-  /**
-   * The browser API for handling selection does not (yet) work for selection
-   * across multiple shadow DOM elements. So we are rendering gr-diff components
-   * into the light DOM instead of the shadow DOM by overriding this method,
-   * which was the recommended workaround by the lit team.
-   * See also https://github.com/WICG/webcomponents/issues/79.
-   */
-  override createRenderRoot() {
-    return this;
-  }
-
-  override render() {
-    return html`
-      <tbody class="gr-diff image-diff">
-        ${this.renderImagePairRow()} ${this.renderImageLabelRow()}
-      </tbody>
-      ${this.renderEndpoint()}
-    `;
-  }
-
-  private renderEndpoint() {
-    return html`
-      <tbody class="gr-diff endpoint">
-        <tr class="gr-diff">
-          <td class="gr-diff" colspan="4">
-            <gr-endpoint-decorator class="gr-diff" name="image-diff">
-              ${this.renderEndpointParam('baseImage', this.baseImage)}
-              ${this.renderEndpointParam('revisionImage', this.revisionImage)}
-            </gr-endpoint-decorator>
-          </td>
-        </tr>
-      </tbody>
-    `;
-  }
-
-  private renderEndpointParam(name: string, value: unknown) {
-    if (!value) return nothing;
-    return html`
-      <gr-endpoint-param class="gr-diff" name=${name} .value=${value}>
-      </gr-endpoint-param>
-    `;
-  }
-
-  private renderImagePairRow() {
-    return html`
-      <tr class="gr-diff">
-        <td class="gr-diff left lineNum blank"></td>
-        <td class="gr-diff left">${this.renderImage(Side.LEFT)}</td>
-        <td class="gr-diff right lineNum blank"></td>
-        <td class="gr-diff right">${this.renderImage(Side.RIGHT)}</td>
-      </tr>
-    `;
-  }
-
-  private renderImage(side: Side) {
-    const image = side === Side.LEFT ? this.baseImage : this.revisionImage;
-    if (!image) return nothing;
-    const error = side === Side.LEFT ? this.baseError : this.revisionError;
-    if (error) return error;
-    const src = imageSrc(image);
-    if (!src) return nothing;
-
-    return html`
-      <img
-        class="gr-diff ${side}"
-        src=${src}
-        @load=${this.handleLoad}
-        @error=${(e: Event) => this.handleError(e, side)}
-      >
-      </img>
-    `;
-  }
-
-  private handleLoad() {
-    this.requestUpdate();
-  }
-
-  private handleError(e: Event, side: Side) {
-    const msg = `[Image failed to load] ${e.type}`;
-    if (side === Side.LEFT) this.baseError = msg;
-    if (side === Side.RIGHT) this.revisionError = msg;
-  }
-
-  private renderImageLabelRow() {
-    return html`
-      <tr class="gr-diff">
-        <td class="gr-diff left lineNum blank"></td>
-        <td class="gr-diff left">
-          <label class="gr-diff">
-            ${this.renderName(this.baseImage?._name ?? '')}
-            <span class="gr-diff label">${this.imageLabel(Side.LEFT)}</span>
-          </label>
-        </td>
-        <td class="gr-diff right lineNum blank"></td>
-        <td class="gr-diff right">
-          <label class="gr-diff">
-            ${this.renderName(this.revisionImage?._name ?? '')}
-            <span class="gr-diff label"> ${this.imageLabel(Side.RIGHT)} </span>
-          </label>
-        </td>
-      </tr>
-    `;
-  }
-
-  private renderName(name?: string) {
-    const addNamesInLabel =
-      this.baseImage &&
-      this.revisionImage &&
-      this.baseImage._name !== this.revisionImage._name;
-    if (!addNamesInLabel) return nothing;
-    return html`
-      <span class="gr-diff name">${name}</span><br class="gr-diff" />
-    `;
-  }
-
-  private imageLabel(side: Side) {
-    const image = side === Side.LEFT ? this.baseImage : this.revisionImage;
-    const imageEl =
-      side === Side.LEFT ? this.baseImageEl : this.revisionImageEl;
-    if (image) {
-      const type = image.type ?? image._expectedType;
-      if (imageEl?.naturalWidth && imageEl.naturalHeight) {
-        return `${imageEl?.naturalWidth}×${imageEl.naturalHeight} ${type}`;
-      } else {
-        return type;
-      }
-    }
-    return 'No image';
-  }
-}
-
-function imageSrc(image?: ImageInfo): string {
-  return image && IMAGE_MIME_PATTERN.test(image.type)
-    ? `data:${image.type};base64,${image.body}`
-    : '';
-}
-
-if (!isNewDiff()) {
-  customElements.define('gr-diff-image-new', GrDiffImageNew);
-  customElements.define('gr-diff-image-old', GrDiffImageOld);
-}
-
-declare global {
-  interface HTMLElementTagNameMap {
-    'gr-diff-image-new': LitElement;
-    'gr-diff-image-old': LitElement;
-  }
-}
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-builder.ts b/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-builder.ts
deleted file mode 100644
index 951466f..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-builder.ts
+++ /dev/null
@@ -1,352 +0,0 @@
-/**
- * @license
- * Copyright 2016 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import './gr-diff-section';
-import '../gr-context-controls/gr-context-controls';
-import {
-  ContentLoadNeededEventDetail,
-  DiffContextExpandedExternalDetail,
-  DiffViewMode,
-  LineNumber,
-  RenderPreferences,
-} from '../../../api/diff';
-import {GrDiffGroup} from '../gr-diff/gr-diff-group';
-import {BlameInfo} from '../../../types/common';
-import {DiffInfo, DiffPreferencesInfo} from '../../../types/diff';
-import {Side} from '../../../constants/constants';
-import {DiffLayer, isDefined} from '../../../types/types';
-import {GrDiffRow} from './gr-diff-row';
-import {GrDiffSection} from './gr-diff-section';
-import {html, render} from 'lit';
-import {diffClasses} from '../../diff/gr-diff/gr-diff-utils';
-import {when} from 'lit/directives/when.js';
-import {GrDiffBuilderImage} from './gr-diff-builder-image';
-import {GrDiffBuilderBinary} from './gr-diff-builder-binary';
-
-export interface DiffContextExpandedEventDetail
-  extends DiffContextExpandedExternalDetail {
-  /** The context control group that should be replaced by `groups`. */
-  contextGroup: GrDiffGroup;
-  groups: GrDiffGroup[];
-}
-
-declare global {
-  interface HTMLElementEventMap {
-    'diff-context-expanded-internal': CustomEvent<DiffContextExpandedEventDetail>;
-    'diff-context-expanded': CustomEvent<DiffContextExpandedExternalDetail>;
-    'content-load-needed': CustomEvent<ContentLoadNeededEventDetail>;
-  }
-}
-
-export function isImageDiffBuilder<T extends GrDiffBuilder>(
-  x: T | GrDiffBuilderImage | undefined
-): x is GrDiffBuilderImage {
-  return !!x && !!(x as GrDiffBuilderImage).renderImageDiff;
-}
-
-export function isBinaryDiffBuilder<T extends GrDiffBuilder>(
-  x: T | GrDiffBuilderBinary | undefined
-): x is GrDiffBuilderBinary {
-  return !!x && !!(x as GrDiffBuilderBinary).renderBinaryDiff;
-}
-
-/**
- * The builder takes GrDiffGroups, and builds the corresponding DOM elements,
- * called sections. Only the builder should add or remove sections from the
- * DOM. Callers can use the ...group() methods to modify groups and thus cause
- * rendering changes.
- */
-export class GrDiffBuilder {
-  private readonly diff: DiffInfo;
-
-  readonly prefs: DiffPreferencesInfo;
-
-  renderPrefs?: RenderPreferences;
-
-  readonly outputEl: HTMLElement;
-
-  private groups: GrDiffGroup[];
-
-  private readonly layerUpdateListener: (
-    start: LineNumber,
-    end: LineNumber,
-    side: Side
-  ) => void;
-
-  constructor(
-    diff: DiffInfo,
-    prefs: DiffPreferencesInfo,
-    outputEl: HTMLElement,
-    readonly layers: DiffLayer[] = [],
-    renderPrefs?: RenderPreferences
-  ) {
-    this.diff = diff;
-    this.prefs = prefs;
-    this.renderPrefs = renderPrefs;
-    this.outputEl = outputEl;
-    this.groups = [];
-
-    if (isNaN(prefs.tab_size) || prefs.tab_size <= 0) {
-      throw Error('Invalid tab size from preferences.');
-    }
-
-    if (isNaN(prefs.line_length) || prefs.line_length <= 0) {
-      throw Error('Invalid line length from preferences.');
-    }
-
-    this.layerUpdateListener = (
-      start: LineNumber,
-      end: LineNumber,
-      side: Side
-    ) => this.renderContentByRange(start, end, side);
-    this.init();
-  }
-
-  getContentTdByLine(
-    lineNumber: LineNumber,
-    side?: Side
-  ): HTMLTableCellElement | undefined {
-    if (!side) return undefined;
-    const row = this.findRow(lineNumber, side);
-    return row?.getContentCell(side);
-  }
-
-  getLineElByNumber(
-    lineNumber: LineNumber,
-    side?: Side
-  ): HTMLTableCellElement | undefined {
-    if (!side) return undefined;
-    const row = this.findRow(lineNumber, side);
-    return row?.getLineNumberCell(side);
-  }
-
-  private findRow(lineNumber?: LineNumber, side?: Side): GrDiffRow | undefined {
-    if (!side || !lineNumber) return undefined;
-    const group = this.findGroup(side, lineNumber);
-    if (!group) return undefined;
-    const section = this.findSection(group);
-    if (!section) return undefined;
-    return section.findRow(side, lineNumber);
-  }
-
-  private getDiffRows() {
-    const sections = [
-      ...this.outputEl.querySelectorAll<GrDiffSection>('gr-diff-section'),
-    ];
-    return sections.map(s => s.getDiffRows()).flat();
-  }
-
-  getLineNumberRows(): HTMLTableRowElement[] {
-    const rows = this.getDiffRows();
-    return rows.map(r => r.getTableRow()).filter(isDefined);
-  }
-
-  getLineNumEls(side: Side): HTMLTableCellElement[] {
-    const rows = this.getDiffRows();
-    return rows.map(r => r.getLineNumberCell(side)).filter(isDefined);
-  }
-
-  /** This is used when layers initiate an update. */
-  renderContentByRange(start: LineNumber, end: LineNumber, side: Side) {
-    const groups = this.getGroupsByLineRange(start, end, side);
-    for (const group of groups) {
-      const section = this.findSection(group);
-      for (const row of section?.getDiffRows() ?? []) {
-        row.requestUpdate();
-      }
-    }
-  }
-
-  private findSection(group: GrDiffGroup): GrDiffSection | undefined {
-    const leftClass = `left-${group.startLine(Side.LEFT)}`;
-    const rightClass = `right-${group.startLine(Side.RIGHT)}`;
-    return (
-      this.outputEl.querySelector<GrDiffSection>(
-        `gr-diff-section.${leftClass}.${rightClass}`
-      ) ?? undefined
-    );
-  }
-
-  buildSectionElement(group: GrDiffGroup): HTMLElement {
-    const leftCl = `left-${group.startLine(Side.LEFT)}`;
-    const rightCl = `right-${group.startLine(Side.RIGHT)}`;
-    const section = html`
-      <gr-diff-section
-        class="${leftCl} ${rightCl}"
-        .group=${group}
-        .diff=${this.diff}
-        .layers=${this.layers}
-        .diffPrefs=${this.prefs}
-        .renderPrefs=${this.renderPrefs}
-      ></gr-diff-section>
-    `;
-    // When using Lit's `render()` method it wants to be in full control of the
-    // element that it renders into, so we let it render into a temp element.
-    // Rendering into the diff table directly would interfere with
-    // `clearDiffContent()`for example.
-    // TODO: Convert <gr-diff> to be fully lit controlled and incorporate this
-    // method into Lit's `render()` cycle.
-    const tempEl = document.createElement('div');
-    render(section, tempEl);
-    const sectionEl = tempEl.firstElementChild as GrDiffSection;
-    return sectionEl;
-  }
-
-  addColumns(outputEl: HTMLElement, lineNumberWidth: number): void {
-    const colgroup = html`
-      <colgroup>
-        <col class=${diffClasses('blame')}></col>
-        ${when(
-          this.renderPrefs?.view_mode === DiffViewMode.UNIFIED,
-          () => html` ${this.renderUnifiedColumns(lineNumberWidth)} `,
-          () => html`
-            ${this.renderSideBySideColumns(Side.LEFT, lineNumberWidth)}
-            ${this.renderSideBySideColumns(Side.RIGHT, lineNumberWidth)}
-          `
-        )}
-      </colgroup>
-    `;
-    // When using Lit's `render()` method it wants to be in full control of the
-    // element that it renders into, so we let it render into a temp element.
-    // Rendering into the diff table directly would interfere with
-    // `clearDiffContent()`for example.
-    // TODO: Convert <gr-diff> to be fully lit controlled and incorporate this
-    // method into Lit's `render()` cycle.
-    const tempEl = document.createElement('div');
-    render(colgroup, tempEl);
-    const colgroupEl = tempEl.firstElementChild as HTMLElement;
-    outputEl.appendChild(colgroupEl);
-  }
-
-  private renderUnifiedColumns(lineNumberWidth: number) {
-    return html`
-      <col class=${diffClasses()} width=${lineNumberWidth}></col>
-      <col class=${diffClasses()} width=${lineNumberWidth}></col>
-      <col class=${diffClasses()}></col>
-    `;
-  }
-
-  private renderSideBySideColumns(side: Side, lineNumberWidth: number) {
-    return html`
-      <col class=${diffClasses(side)} width=${lineNumberWidth}></col>
-      <col class=${diffClasses(side, 'sign')}></col>
-      <col class=${diffClasses(side)}></col>
-    `;
-  }
-
-  /**
-   * This is meant to be called when the gr-diff component re-connects, or when
-   * the diff is (re-)rendered.
-   *
-   * Make sure that this method is symmetric with cleanup(), which is called
-   * when gr-diff disconnects.
-   */
-  init() {
-    this.cleanup();
-    for (const layer of this.layers) {
-      if (layer.addListener) {
-        layer.addListener(this.layerUpdateListener);
-      }
-    }
-  }
-
-  /**
-   * This is meant to be called when the gr-diff component disconnects, or when
-   * the diff is (re-)rendered.
-   *
-   * Make sure that this method is symmetric with init(), which is called when
-   * gr-diff re-connects.
-   */
-  cleanup() {
-    for (const layer of this.layers) {
-      if (layer.removeListener) {
-        layer.removeListener(this.layerUpdateListener);
-      }
-    }
-  }
-
-  addGroups(groups: readonly GrDiffGroup[]) {
-    for (const group of groups) {
-      this.groups.push(group);
-      this.emitGroup(group);
-    }
-  }
-
-  clearGroups() {
-    for (const deletedGroup of this.groups) {
-      deletedGroup.element?.remove();
-    }
-    this.groups = [];
-  }
-
-  replaceGroup(contextControl: GrDiffGroup, groups: readonly GrDiffGroup[]) {
-    const i = this.groups.indexOf(contextControl);
-    if (i === -1) throw new Error('cannot find context control group');
-
-    const contextControlSection = this.groups[i].element;
-    if (!contextControlSection) throw new Error('diff group element not set');
-
-    this.groups.splice(i, 1, ...groups);
-    for (const group of groups) {
-      this.emitGroup(group, contextControlSection);
-    }
-    if (contextControlSection) contextControlSection.remove();
-  }
-
-  findGroup(side: Side, line: LineNumber) {
-    return this.groups.find(group => group.containsLine(side, line));
-  }
-
-  private emitGroup(group: GrDiffGroup, beforeSection?: HTMLElement) {
-    const element = this.buildSectionElement(group);
-    this.outputEl.insertBefore(element, beforeSection ?? null);
-    group.element = element;
-  }
-
-  // visible for testing
-  getGroupsByLineRange(
-    startLine: LineNumber,
-    endLine: LineNumber,
-    side: Side
-  ): GrDiffGroup[] {
-    const startIndex = this.groups.findIndex(group =>
-      group.containsLine(side, startLine)
-    );
-    if (startIndex === -1) return [];
-    let endIndex = this.groups.findIndex(group =>
-      group.containsLine(side, endLine)
-    );
-    // Not all groups may have been processed yet (i.e. this.groups is still
-    // incomplete). In that case let's just return *all* groups until the end
-    // of the array.
-    if (endIndex === -1) endIndex = this.groups.length - 1;
-    // The filter preserves the legacy behavior to only return non-context
-    // groups
-    return this.groups
-      .slice(startIndex, endIndex + 1)
-      .filter(group => group.lines.length > 0);
-  }
-
-  /**
-   * Set the blame information for the diff. For any already-rendered line,
-   * re-render its blame cell content.
-   */
-  setBlame(blame: BlameInfo[]) {
-    for (const blameInfo of blame) {
-      for (const range of blameInfo.ranges) {
-        for (let line = range.start; line <= range.end; line++) {
-          const row = this.findRow(line, Side.LEFT);
-          if (row) row.blameInfo = blameInfo;
-        }
-      }
-    }
-  }
-
-  /**
-   * Only special builders need to implement this. The default is to
-   * just ignore it.
-   */
-  updateRenderPrefs(_: RenderPreferences) {}
-}
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-row.ts b/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-row.ts
deleted file mode 100644
index 1486154..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-row.ts
+++ /dev/null
@@ -1,487 +0,0 @@
-/**
- * @license
- * Copyright 2022 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import {html, LitElement, nothing, TemplateResult} from 'lit';
-import {property, state} from 'lit/decorators.js';
-import {ifDefined} from 'lit/directives/if-defined.js';
-import {createRef, Ref, ref} from 'lit/directives/ref.js';
-import {
-  DiffResponsiveMode,
-  Side,
-  LineNumber,
-  DiffLayer,
-  GrDiffLineType,
-  LOST,
-  FILE,
-} from '../../../api/diff';
-import {BlameInfo} from '../../../types/common';
-import {assertIsDefined} from '../../../utils/common-util';
-import {fire} from '../../../utils/event-util';
-import {getBaseUrl} from '../../../utils/url-util';
-import './gr-diff-text';
-import {GrDiffLine} from '../gr-diff/gr-diff-line';
-import {
-  diffClasses,
-  isNewDiff,
-  isResponsive,
-} from '../../diff/gr-diff/gr-diff-utils';
-
-export class GrDiffRow extends LitElement {
-  contentLeftRef: Ref<LitElement> = createRef();
-
-  contentRightRef: Ref<LitElement> = createRef();
-
-  contentCellLeftRef: Ref<HTMLTableCellElement> = createRef();
-
-  contentCellRightRef: Ref<HTMLTableCellElement> = createRef();
-
-  lineNumberLeftRef: Ref<HTMLTableCellElement> = createRef();
-
-  lineNumberRightRef: Ref<HTMLTableCellElement> = createRef();
-
-  blameCellRef: Ref<HTMLTableCellElement> = createRef();
-
-  tableRowRef: Ref<HTMLTableRowElement> = createRef();
-
-  @property({type: Object})
-  left?: GrDiffLine;
-
-  @property({type: Object})
-  right?: GrDiffLine;
-
-  @property({type: Object})
-  blameInfo?: BlameInfo;
-
-  @property({type: Object})
-  responsiveMode?: DiffResponsiveMode;
-
-  /**
-   * true: side-by-side diff
-   * false: unified diff
-   */
-  @property({type: Boolean})
-  unifiedDiff = false;
-
-  @property({type: Number})
-  tabSize = 2;
-
-  @property({type: Number})
-  lineLength = 80;
-
-  @property({type: Boolean})
-  hideFileCommentButton = false;
-
-  @property({type: Object})
-  layers: DiffLayer[] = [];
-
-  /**
-   * Semantic DOM diff testing does not work with just table fragments, so when
-   * running such tests the render() method has to wrap the DOM in a proper
-   * <table> element.
-   */
-  @state()
-  addTableWrapperForTesting = false;
-
-  /**
-   * Keeps track of whether diff layers have already been applied to the diff
-   * row. That happens after the DOM has been created in the `updated()`
-   * lifecycle callback.
-   *
-   * Once layers are applied, the diff row requires two rendering passes for an
-   * update: 1. Remove all <gr-diff-text> elements and their layer manipulated
-   * DOMs. 2. Add fresh <gr-diff-text> elements and let layers re-apply in
-   * `updated()`.
-   */
-  private layersApplied = false;
-
-  /**
-   * The browser API for handling selection does not (yet) work for selection
-   * across multiple shadow DOM elements. So we are rendering gr-diff components
-   * into the light DOM instead of the shadow DOM by overriding this method,
-   * which was the recommended workaround by the lit team.
-   * See also https://github.com/WICG/webcomponents/issues/79.
-   */
-  override createRenderRoot() {
-    return this;
-  }
-
-  override updated() {
-    if (this.layersApplied) {
-      // <gr-diff-text> elements have been removed during rendering. Let's start
-      // another rendering cycle with freshly created <gr-diff-text> elements.
-      this.updateComplete.then(() => {
-        this.layersApplied = false;
-        this.requestUpdate();
-      });
-    } else {
-      this.updateLayers(Side.LEFT);
-      this.updateLayers(Side.RIGHT);
-    }
-  }
-
-  /**
-   * The diff layers API is designed to let layers manipulate the DOM. So we
-   * have to apply them after the rendering cycle is done (`updated()`). But
-   * when re-rendering a row that already has layers applied, then we have to
-   * first wipe away <gr-diff-text>. This is achieved by
-   * `this.layersApplied = true`.
-   */
-  private async updateLayers(side: Side) {
-    const line = this.line(side);
-    const contentEl = this.contentRef(side).value;
-    const lineNumberEl = this.lineNumberRef(side).value;
-    if (!line || !contentEl || !lineNumberEl) return;
-
-    // We have to wait for the <gr-diff-text> child component to finish
-    // rendering before we can apply layers, which will re-write the HTML.
-    await contentEl?.updateComplete;
-    for (const layer of this.layers) {
-      if (typeof layer.annotate === 'function') {
-        layer.annotate(contentEl, lineNumberEl, line, side);
-      }
-    }
-    // At this point we consider layers applied. So as soon as <gr-diff-row>
-    // enters a new rendering cycle <gr-diff-text> elements will be removed.
-    this.layersApplied = true;
-  }
-
-  override render() {
-    if (!this.left || !this.right) return;
-    const classes = this.unifiedDiff ? ['unified'] : ['side-by-side'];
-    const unifiedType = this.unifiedType();
-    if (this.unifiedDiff && unifiedType) classes.push(unifiedType);
-    const row = html`
-      <tr
-        ${ref(this.tableRowRef)}
-        class=${diffClasses('diff-row', ...classes)}
-        left-type=${ifDefined(this.getType(Side.LEFT))}
-        right-type=${ifDefined(this.getType(Side.RIGHT))}
-        tabindex="-1"
-        aria-labelledby=${this.ariaLabelIds()}
-      >
-        ${this.renderBlameCell()} ${this.renderLineNumberCell(Side.LEFT)}
-        ${this.renderSignCell(Side.LEFT)} ${this.renderContentCell(Side.LEFT)}
-        ${this.renderLineNumberCell(Side.RIGHT)}
-        ${this.renderSignCell(Side.RIGHT)} ${this.renderContentCell(Side.RIGHT)}
-      </tr>
-      ${this.renderPostLineSlot(Side.LEFT)}
-      ${this.renderPostLineSlot(Side.RIGHT)}
-    `;
-    if (this.addTableWrapperForTesting) {
-      return html`<table>
-        ${row}
-      </table>`;
-    }
-    return row;
-  }
-
-  private ariaLabelIds() {
-    const ids: string[] = [];
-    ids.push(this.lineNumberId(Side.LEFT));
-    if (!this.unifiedDiff) ids.push(this.contentId(Side.LEFT));
-    ids.push(this.lineNumberId(Side.RIGHT));
-    if (!this.unifiedDiff) ids.push(this.contentId(Side.RIGHT));
-    if (this.unifiedDiff) ids.push(this.contentId(this.unifiedSide()));
-    return ids.filter(id => !!id).join(' ');
-  }
-
-  private lineNumberId(side: Side): string {
-    const lineNumber = this.lineNumber(side);
-    if (!lineNumber) return '';
-    return `${side}-button-${lineNumber}`;
-  }
-
-  private unifiedSide() {
-    const isLeft = this.line(Side.RIGHT)?.type === GrDiffLineType.BLANK;
-    return isLeft ? Side.LEFT : Side.RIGHT;
-  }
-
-  private contentId(side: Side): string {
-    const lineNumber = this.lineNumber(side);
-    if (!lineNumber) return '';
-    return `${side}-content-${lineNumber}`;
-  }
-
-  getTableRow(): HTMLTableRowElement | undefined {
-    return this.tableRowRef.value;
-  }
-
-  getLineNumberCell(side: Side): HTMLTableCellElement | undefined {
-    return this.lineNumberRef(side).value;
-  }
-
-  getContentCell(side: Side) {
-    return this.contentCellRef(side)?.value;
-  }
-
-  getBlameCell() {
-    return this.blameCellRef.value;
-  }
-
-  private renderBlameCell() {
-    // td.blame has `white-space: pre`, so prettier must not add spaces.
-    // prettier-ignore
-    return html`
-      <td
-        ${ref(this.blameCellRef)}
-        class=${diffClasses('blame')}
-        data-line-number=${this.left?.beforeNumber ?? 0}
-      >${this.renderBlameElement()}</td>
-    `;
-  }
-
-  private renderBlameElement() {
-    const lineNum = this.left?.beforeNumber;
-    const commit = this.blameInfo;
-    if (!lineNum || !commit) return;
-
-    const isStartOfRange = commit.ranges.some(r => r.start === lineNum);
-    const extras: string[] = [];
-    if (isStartOfRange) extras.push('startOfRange');
-    const date = new Date(commit.time * 1000).toLocaleDateString();
-    const shortName = commit.author.split(' ')[0];
-    const url = `${getBaseUrl()}/q/${commit.id}`;
-
-    // td.blame has `white-space: pre`, so prettier must not add spaces.
-    // prettier-ignore
-    return html`<span class=${diffClasses(...extras)}
-        ><a href=${url} class=${diffClasses('blameDate')}>${date}</a
-        ><span class=${diffClasses('blameAuthor')}> ${shortName}</span
-        ><gr-hovercard class=${diffClasses()}>
-          <span class=${diffClasses('blameHoverCard')}>
-            Commit ${commit.id}<br />
-            Author: ${commit.author}<br />
-            Date: ${date}<br />
-            <br />
-            ${commit.commit_msg}
-          </span>
-        </gr-hovercard
-      ></span>`;
-  }
-
-  private renderLineNumberCell(side: Side): TemplateResult {
-    const line = this.line(side);
-    const lineNumber = this.lineNumber(side);
-    const isBlank = line?.type === GrDiffLineType.BLANK;
-    if (!line || !lineNumber || isBlank || this.layersApplied) {
-      const blankClass = isBlank && !this.unifiedDiff ? 'blankLineNum' : '';
-      return html`<td
-        ${ref(this.lineNumberRef(side))}
-        class=${diffClasses(side, blankClass)}
-      ></td>`;
-    }
-
-    return html`<td
-      ${ref(this.lineNumberRef(side))}
-      class=${diffClasses(side, 'lineNum')}
-      data-value=${lineNumber}
-    >
-      ${this.renderLineNumberButton(line, lineNumber, side)}
-    </td>`;
-  }
-
-  private renderLineNumberButton(
-    line: GrDiffLine,
-    lineNumber: LineNumber,
-    side: Side
-  ) {
-    if (this.hideFileCommentButton && lineNumber === FILE) return;
-    if (lineNumber === LOST) return;
-    // .lineNumButton has `white-space: pre`, so prettier must not add spaces.
-    // prettier-ignore
-    return html`
-      <button
-        id=${this.lineNumberId(side)}
-        class=${diffClasses('lineNumButton', side)}
-        tabindex="-1"
-        data-value=${lineNumber}
-        aria-label=${ifDefined(
-          this.computeLineNumberAriaLabel(line, lineNumber)
-        )}
-        @mouseenter=${() =>
-          fire(this, 'line-mouse-enter', {lineNum: lineNumber, side})}
-        @mouseleave=${() =>
-          fire(this, 'line-mouse-leave', {lineNum: lineNumber, side})}
-      >${lineNumber === FILE ? 'File' : lineNumber.toString()}</button>
-    `;
-  }
-
-  private computeLineNumberAriaLabel(line: GrDiffLine, lineNumber: LineNumber) {
-    if (lineNumber === FILE) return 'Add file comment';
-
-    // Add aria-labels for valid line numbers.
-    // For unified diff, this method will be called with number set to 0 for
-    // the empty line number column for added/removed lines. This should not
-    // be announced to the screenreader.
-    if (
-      lineNumber === LOST ||
-      (typeof lineNumber === 'number' && lineNumber <= 0)
-    )
-      return undefined;
-    switch (line.type) {
-      case GrDiffLineType.REMOVE:
-        return `${lineNumber} removed`;
-      case GrDiffLineType.ADD:
-        return `${lineNumber} added`;
-      case GrDiffLineType.BOTH:
-      case GrDiffLineType.BLANK:
-        return `${lineNumber} unmodified`;
-    }
-  }
-
-  private renderContentCell(side: Side) {
-    let line = this.line(side);
-    if (this.unifiedDiff) {
-      if (side === Side.LEFT) return nothing;
-      if (line?.type === GrDiffLineType.BLANK) {
-        side = Side.LEFT;
-        line = this.line(Side.LEFT);
-      }
-    }
-    const lineNumber = this.lineNumber(side);
-    assertIsDefined(line, 'line');
-    const extras: string[] = [line.type, side];
-    if (line.type !== GrDiffLineType.BLANK) extras.push('content');
-    if (!line.hasIntralineInfo) extras.push('no-intraline-info');
-    if (line.beforeNumber === FILE) extras.push('file');
-    if (line.beforeNumber === LOST) extras.push('lost');
-
-    // .content has `white-space: pre`, so prettier must not add spaces.
-    // prettier-ignore
-    return html`
-      <td
-        ${ref(this.contentCellRef(side))}
-        class=${diffClasses(...extras)}
-        @mouseenter=${() => {
-          if (lineNumber)
-            fire(this, 'line-mouse-enter', {lineNum: lineNumber, side});
-        }}
-        @mouseleave=${() => {
-          if (lineNumber)
-            fire(this, 'line-mouse-leave', {lineNum: lineNumber, side});
-        }}
-      >${this.renderText(side)}${this.renderThreadGroup(side)}</td>
-    `;
-  }
-
-  private renderSignCell(side: Side) {
-    if (this.unifiedDiff) return nothing;
-    const line = this.line(side);
-    assertIsDefined(line, 'line');
-    const isBlank = line.type === GrDiffLineType.BLANK;
-    const isAdd = line.type === GrDiffLineType.ADD && side === Side.RIGHT;
-    const isRemove = line.type === GrDiffLineType.REMOVE && side === Side.LEFT;
-    const extras: string[] = ['sign', side];
-    if (isBlank) extras.push('blank');
-    if (isAdd) extras.push('add');
-    if (isRemove) extras.push('remove');
-    if (!line.hasIntralineInfo) extras.push('no-intraline-info');
-
-    const sign = isAdd ? '+' : isRemove ? '-' : '';
-    return html`<td class=${diffClasses(...extras)}>${sign}</td>`;
-  }
-
-  private renderThreadGroup(side: Side) {
-    const lineNumber = this.lineNumber(side);
-    if (!lineNumber) return nothing;
-    return html`<div class="thread-group" data-side=${side}>
-      <slot name="${side}-${lineNumber}"></slot>
-      ${this.renderSecondSlot()}
-    </div>`;
-  }
-
-  private renderSecondSlot() {
-    if (!this.unifiedDiff) return nothing;
-    if (this.line(Side.LEFT)?.type !== GrDiffLineType.BOTH) return nothing;
-    return html`<slot
-      name="${Side.LEFT}-${this.lineNumber(Side.LEFT)}"
-    ></slot>`;
-  }
-
-  private contentRef(side: Side) {
-    return side === Side.LEFT ? this.contentLeftRef : this.contentRightRef;
-  }
-
-  private contentCellRef(side: Side) {
-    return side === Side.LEFT
-      ? this.contentCellLeftRef
-      : this.contentCellRightRef;
-  }
-
-  private lineNumberRef(side: Side) {
-    return side === Side.LEFT
-      ? this.lineNumberLeftRef
-      : this.lineNumberRightRef;
-  }
-
-  private lineNumber(side: Side) {
-    return this.line(side)?.lineNumber(side);
-  }
-
-  private line(side: Side) {
-    return side === Side.LEFT ? this.left : this.right;
-  }
-
-  private getType(side?: Side): string | undefined {
-    if (this.unifiedDiff) return undefined;
-    if (side === Side.LEFT) return this.left?.type;
-    if (side === Side.RIGHT) return this.right?.type;
-    return undefined;
-  }
-
-  private unifiedType() {
-    return this.left?.type === GrDiffLineType.BLANK
-      ? this.right?.type
-      : this.left?.type;
-  }
-
-  /**
-   * Returns a 'div' element containing the supplied |text| as its innerText,
-   * with '\t' characters expanded to a width determined by |tabSize|, and the
-   * text wrapped at column |lineLimit|, which may be Infinity if no wrapping is
-   * desired.
-   */
-  private renderText(side: Side) {
-    const line = this.line(side);
-    const lineNumber = this.lineNumber(side);
-    if (typeof lineNumber !== 'number') return;
-
-    // Note that `this.layersApplied` will wipe away the <gr-diff-text>, and
-    // another rendering cycle will be initiated in `updated()`.
-    // prettier-ignore
-    const textElement = line?.text && !this.layersApplied
-      ? html`<gr-diff-text
-          ${ref(this.contentRef(side))}
-          .text=${line?.text}
-          .tabSize=${this.tabSize}
-          .lineLimit=${this.lineLength}
-          .isResponsive=${isResponsive(this.responsiveMode)}
-        ></gr-diff-text>` : '';
-    // .content has `white-space: pre`, so prettier must not add spaces.
-    // prettier-ignore
-    return html`<div
-        class=${diffClasses('contentText')}
-        data-side=${ifDefined(side)}
-        id=${this.contentId(side)}
-      >${textElement}</div>`;
-  }
-
-  private renderPostLineSlot(side: Side) {
-    const lineNumber = this.lineNumber(side);
-    return lineNumber && Number.isInteger(lineNumber)
-      ? html`<slot name="post-${side}-line-${lineNumber}"></slot>`
-      : nothing;
-  }
-}
-
-if (!isNewDiff()) {
-  customElements.define('gr-diff-row', GrDiffRow);
-}
-
-declare global {
-  interface HTMLElementTagNameMap {
-    'gr-diff-row': LitElement;
-  }
-}
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-row_test.ts b/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-row_test.ts
deleted file mode 100644
index 42d30aa..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-row_test.ts
+++ /dev/null
@@ -1,271 +0,0 @@
-/**
- * @license
- * Copyright 2022 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import '../../../test/common-test-setup';
-import './gr-diff-row';
-import {GrDiffRow} from './gr-diff-row';
-import {fixture, html, assert} from '@open-wc/testing';
-import {GrDiffLine} from '../gr-diff/gr-diff-line';
-import {GrDiffLineType} from '../../../api/diff';
-
-suite('gr-diff-row test', () => {
-  let element: GrDiffRow;
-
-  setup(async () => {
-    element = await fixture<GrDiffRow>(html`<gr-diff-row></gr-diff-row>`);
-    element.addTableWrapperForTesting = true;
-    await element.updateComplete;
-  });
-
-  test('both', async () => {
-    const line = new GrDiffLine(GrDiffLineType.BOTH, 1, 1);
-    line.text = 'lorem ipsum';
-    element.left = line;
-    element.right = line;
-    await element.updateComplete;
-    assert.lightDom.equal(
-      element,
-      /* HTML */ `
-        <table>
-          <tbody>
-            <tr
-              aria-labelledby="left-button-1 left-content-1 right-button-1 right-content-1"
-              class="diff-row gr-diff side-by-side"
-              left-type="both"
-              right-type="both"
-              tabindex="-1"
-            >
-              <td class="blame gr-diff" data-line-number="1"></td>
-              <td class="gr-diff left lineNum" data-value="1">
-                <button
-                  aria-label="1 unmodified"
-                  class="gr-diff left lineNumButton"
-                  data-value="1"
-                  id="left-button-1"
-                  tabindex="-1"
-                >
-                  1
-                </button>
-              </td>
-              <td class="gr-diff left no-intraline-info sign"></td>
-              <td class="both content gr-diff left no-intraline-info">
-                <div
-                  class="contentText gr-diff"
-                  data-side="left"
-                  id="left-content-1"
-                >
-                  <gr-diff-text> lorem ipsum </gr-diff-text>
-                </div>
-                <div class="thread-group" data-side="left">
-                  <slot name="left-1"> </slot>
-                </div>
-              </td>
-              <td class="gr-diff lineNum right" data-value="1">
-                <button
-                  aria-label="1 unmodified"
-                  class="gr-diff lineNumButton right"
-                  data-value="1"
-                  id="right-button-1"
-                  tabindex="-1"
-                >
-                  1
-                </button>
-              </td>
-              <td class="gr-diff no-intraline-info right sign"></td>
-              <td class="both content gr-diff no-intraline-info right">
-                <div
-                  class="contentText gr-diff"
-                  data-side="right"
-                  id="right-content-1"
-                >
-                  <gr-diff-text> lorem ipsum </gr-diff-text>
-                </div>
-                <div class="thread-group" data-side="right">
-                  <slot name="right-1"> </slot>
-                </div>
-              </td>
-            </tr>
-            <slot name="post-left-line-1"></slot>
-            <slot name="post-right-line-1"></slot>
-          </tbody>
-        </table>
-      `
-    );
-  });
-
-  test('both unified', async () => {
-    const line = new GrDiffLine(GrDiffLineType.BOTH, 1, 1);
-    line.text = 'lorem ipsum';
-    element.left = line;
-    element.right = line;
-    element.unifiedDiff = true;
-    await element.updateComplete;
-    assert.lightDom.equal(
-      element,
-      /* HTML */ `
-        <table>
-          <tbody>
-            <tr
-              aria-labelledby="left-button-1 right-button-1 right-content-1"
-              class="both diff-row gr-diff unified"
-              tabindex="-1"
-            >
-              <td class="blame gr-diff" data-line-number="1"></td>
-              <td class="gr-diff left lineNum" data-value="1">
-                <button
-                  aria-label="1 unmodified"
-                  class="gr-diff left lineNumButton"
-                  data-value="1"
-                  id="left-button-1"
-                  tabindex="-1"
-                >
-                  1
-                </button>
-              </td>
-              <td class="gr-diff lineNum right" data-value="1">
-                <button
-                  aria-label="1 unmodified"
-                  class="gr-diff lineNumButton right"
-                  data-value="1"
-                  id="right-button-1"
-                  tabindex="-1"
-                >
-                  1
-                </button>
-              </td>
-              <td class="both content gr-diff no-intraline-info right">
-                <div
-                  class="contentText gr-diff"
-                  data-side="right"
-                  id="right-content-1"
-                >
-                  <gr-diff-text> lorem ipsum </gr-diff-text>
-                </div>
-                <div class="thread-group" data-side="right">
-                  <slot name="right-1"> </slot>
-                  <slot name="left-1"> </slot>
-                </div>
-              </td>
-            </tr>
-            <slot name="post-left-line-1"></slot>
-            <slot name="post-right-line-1"></slot>
-          </tbody>
-        </table>
-      `
-    );
-  });
-
-  test('add', async () => {
-    const line = new GrDiffLine(GrDiffLineType.ADD, 0, 1);
-    line.text = 'lorem ipsum';
-    element.left = new GrDiffLine(GrDiffLineType.BLANK);
-    element.right = line;
-    await element.updateComplete;
-    assert.lightDom.equal(
-      element,
-      /* HTML */ `
-        <table>
-          <tbody>
-            <tr
-              aria-labelledby="right-button-1 right-content-1"
-              class="diff-row gr-diff side-by-side"
-              left-type="blank"
-              right-type="add"
-              tabindex="-1"
-            >
-              <td class="blame gr-diff" data-line-number="0"></td>
-              <td class="blankLineNum gr-diff left"></td>
-              <td class="blank gr-diff left no-intraline-info sign"></td>
-              <td class="blank gr-diff left no-intraline-info">
-                <div class="contentText gr-diff" data-side="left"></div>
-              </td>
-              <td class="gr-diff lineNum right" data-value="1">
-                <button
-                  aria-label="1 added"
-                  class="gr-diff lineNumButton right"
-                  data-value="1"
-                  id="right-button-1"
-                  tabindex="-1"
-                >
-                  1
-                </button>
-              </td>
-              <td class="add gr-diff no-intraline-info right sign">+</td>
-              <td class="add content gr-diff no-intraline-info right">
-                <div
-                  class="contentText gr-diff"
-                  data-side="right"
-                  id="right-content-1"
-                >
-                  <gr-diff-text> lorem ipsum </gr-diff-text>
-                </div>
-                <div class="thread-group" data-side="right">
-                  <slot name="right-1"> </slot>
-                </div>
-              </td>
-              <slot name="post-right-line-1"></slot>
-            </tr>
-          </tbody>
-        </table>
-      `
-    );
-  });
-
-  test('remove', async () => {
-    const line = new GrDiffLine(GrDiffLineType.REMOVE, 1, 0);
-    line.text = 'lorem ipsum';
-    element.left = line;
-    element.right = new GrDiffLine(GrDiffLineType.BLANK);
-    await element.updateComplete;
-    assert.lightDom.equal(
-      element,
-      /* HTML */ `
-        <table>
-          <tbody>
-            <tr
-              aria-labelledby="left-button-1 left-content-1"
-              class="diff-row gr-diff side-by-side"
-              left-type="remove"
-              right-type="blank"
-              tabindex="-1"
-            >
-              <td class="blame gr-diff" data-line-number="1"></td>
-              <td class="gr-diff left lineNum" data-value="1">
-                <button
-                  aria-label="1 removed"
-                  class="gr-diff left lineNumButton"
-                  data-value="1"
-                  id="left-button-1"
-                  tabindex="-1"
-                >
-                  1
-                </button>
-              </td>
-              <td class="gr-diff left no-intraline-info remove sign">-</td>
-              <td class="content gr-diff left no-intraline-info remove">
-                <div
-                  class="contentText gr-diff"
-                  data-side="left"
-                  id="left-content-1"
-                >
-                  <gr-diff-text> lorem ipsum </gr-diff-text>
-                </div>
-                <div class="thread-group" data-side="left">
-                  <slot name="left-1"> </slot>
-                </div>
-              </td>
-              <td class="blankLineNum gr-diff right"></td>
-              <td class="blank gr-diff no-intraline-info right sign"></td>
-              <td class="blank gr-diff no-intraline-info right">
-                <div class="contentText gr-diff" data-side="right"></div>
-              </td>
-            </tr>
-            <slot name="post-left-line-1"></slot>
-          </tbody>
-        </table>
-      `
-    );
-  });
-});
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-section.ts b/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-section.ts
deleted file mode 100644
index 28919e8..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-section.ts
+++ /dev/null
@@ -1,254 +0,0 @@
-/**
- * @license
- * Copyright 2022 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import {html, LitElement} from 'lit';
-import {property, state} from 'lit/decorators.js';
-import {
-  DiffInfo,
-  DiffLayer,
-  DiffViewMode,
-  RenderPreferences,
-  Side,
-  LineNumber,
-  DiffPreferencesInfo,
-} from '../../../api/diff';
-import {GrDiffGroup, GrDiffGroupType} from '../gr-diff/gr-diff-group';
-import {
-  diffClasses,
-  getResponsiveMode,
-  isNewDiff,
-} from '../../diff/gr-diff/gr-diff-utils';
-import {GrDiffRow} from './gr-diff-row';
-import '../gr-context-controls/gr-context-controls-section';
-import '../gr-context-controls/gr-context-controls';
-import '../../diff/gr-range-header/gr-range-header';
-import './gr-diff-row';
-import {when} from 'lit/directives/when.js';
-import {fire} from '../../../utils/event-util';
-import {countLines} from '../../../utils/diff-util';
-
-export class GrDiffSection extends LitElement {
-  @property({type: Object})
-  group?: GrDiffGroup;
-
-  @property({type: Object})
-  diff?: DiffInfo;
-
-  @property({type: Object})
-  renderPrefs?: RenderPreferences;
-
-  @property({type: Object})
-  diffPrefs?: DiffPreferencesInfo;
-
-  @property({type: Object})
-  layers: DiffLayer[] = [];
-
-  /**
-   * Semantic DOM diff testing does not work with just table fragments, so when
-   * running such tests the render() method has to wrap the DOM in a proper
-   * <table> element.
-   */
-  @state()
-  addTableWrapperForTesting = false;
-
-  /**
-   * The browser API for handling selection does not (yet) work for selection
-   * across multiple shadow DOM elements. So we are rendering gr-diff components
-   * into the light DOM instead of the shadow DOM by overriding this method,
-   * which was the recommended workaround by the lit team.
-   * See also https://github.com/WICG/webcomponents/issues/79.
-   */
-  override createRenderRoot() {
-    return this;
-  }
-
-  override render() {
-    if (!this.group) return;
-    const extras: string[] = [];
-    extras.push('section');
-    extras.push(this.group.type);
-    if (this.group.isTotal()) extras.push('total');
-    if (this.group.dueToRebase) extras.push('dueToRebase');
-    if (this.group.moveDetails) extras.push('dueToMove');
-    if (this.group.moveDetails?.changed) extras.push('changed');
-    if (this.group.ignoredWhitespaceOnly) extras.push('ignoredWhitespaceOnly');
-
-    const pairs = this.getLinePairs();
-    const responsiveMode = getResponsiveMode(this.diffPrefs, this.renderPrefs);
-    const hideFileCommentButton =
-      this.diffPrefs?.show_file_comment_button === false ||
-      this.renderPrefs?.show_file_comment_button === false;
-    const body = html`
-      <tbody class=${diffClasses(...extras)}>
-        ${this.renderContextControls()} ${this.renderMoveControls()}
-        ${pairs.map(pair => {
-          const leftCl = `left-${pair.left.lineNumber(Side.LEFT)}`;
-          const rightCl = `right-${pair.right.lineNumber(Side.RIGHT)}`;
-          return html`
-            <gr-diff-row
-              class="${leftCl} ${rightCl}"
-              .left=${pair.left}
-              .right=${pair.right}
-              .layers=${this.layers}
-              .lineLength=${this.diffPrefs?.line_length ?? 80}
-              .tabSize=${this.diffPrefs?.tab_size ?? 2}
-              .unifiedDiff=${this.isUnifiedDiff()}
-              .responsiveMode=${responsiveMode}
-              .hideFileCommentButton=${hideFileCommentButton}
-            >
-            </gr-diff-row>
-          `;
-        })}
-      </tbody>
-    `;
-    if (this.addTableWrapperForTesting) {
-      return html`<table>
-        ${body}
-      </table>`;
-    }
-    return body;
-  }
-
-  private isUnifiedDiff() {
-    return this.renderPrefs?.view_mode === DiffViewMode.UNIFIED;
-  }
-
-  getLinePairs() {
-    if (!this.group) return [];
-    const isControl = this.group.type === GrDiffGroupType.CONTEXT_CONTROL;
-    if (isControl) return [];
-    return this.isUnifiedDiff()
-      ? this.group.getUnifiedPairs()
-      : this.group.getSideBySidePairs();
-  }
-
-  getDiffRows(): GrDiffRow[] {
-    return [...this.querySelectorAll<GrDiffRow>('gr-diff-row')];
-  }
-
-  private renderContextControls() {
-    if (this.group?.type !== GrDiffGroupType.CONTEXT_CONTROL) return;
-
-    const leftStart = this.group.lineRange.left.start_line;
-    const leftEnd = this.group.lineRange.left.end_line;
-    const firstGroupIsSkipped = !!this.group.contextGroups[0].skip;
-    const lastGroupIsSkipped =
-      !!this.group.contextGroups[this.group.contextGroups.length - 1].skip;
-    const lineCountLeft = countLines(this.diff, Side.LEFT);
-    const containsWholeFile = lineCountLeft === leftEnd - leftStart + 1;
-    const showAbove =
-      (leftStart > 1 && !firstGroupIsSkipped) || containsWholeFile;
-    const showBelow = leftEnd < lineCountLeft && !lastGroupIsSkipped;
-
-    return html`
-      <gr-context-controls-section
-        .showAbove=${showAbove}
-        .showBelow=${showBelow}
-        .group=${this.group}
-        .diff=${this.diff}
-        .renderPrefs=${this.renderPrefs}
-      >
-      </gr-context-controls-section>
-    `;
-  }
-
-  findRow(side: Side, lineNumber: LineNumber): GrDiffRow | undefined {
-    return (
-      this.querySelector<GrDiffRow>(`gr-diff-row.${side}-${lineNumber}`) ??
-      undefined
-    );
-  }
-
-  private renderMoveControls() {
-    if (!this.group?.moveDetails) return;
-    const movedIn = this.group.adds.length > 0;
-    const plainCell = html`<td class=${diffClasses()}></td>`;
-    const signCell = html`<td class=${diffClasses('sign')}></td>`;
-    const lineNumberCell = html`
-      <td class=${diffClasses('moveControlsLineNumCol')}></td>
-    `;
-    const moveCell = html`
-      <td class=${diffClasses('moveHeader')}>
-        <gr-range-header class=${diffClasses()} icon="move_item">
-          ${this.renderMoveDescription(movedIn)}
-        </gr-range-header>
-      </td>
-    `;
-    return html`
-      <tr
-        class=${diffClasses('moveControls', movedIn ? 'movedIn' : 'movedOut')}
-      >
-        ${when(
-          this.isUnifiedDiff(),
-          () => html`${lineNumberCell} ${lineNumberCell} ${moveCell}`,
-          () => html`${lineNumberCell} ${signCell}
-          ${movedIn ? plainCell : moveCell} ${lineNumberCell} ${signCell}
-          ${movedIn ? moveCell : plainCell}`
-        )}
-      </tr>
-    `;
-  }
-
-  private renderMoveDescription(movedIn: boolean) {
-    if (this.group?.moveDetails?.range) {
-      const {changed, range} = this.group.moveDetails;
-      const otherSide = movedIn ? Side.LEFT : Side.RIGHT;
-      const andChangedLabel = changed ? 'and changed ' : '';
-      const direction = movedIn ? 'from' : 'to';
-      const textLabel = `Moved ${andChangedLabel}${direction} lines `;
-      return html`
-        <div class=${diffClasses()}>
-          <span class=${diffClasses()}>${textLabel}</span>
-          ${this.renderMovedLineAnchor(range.start, otherSide)}
-          <span class=${diffClasses()}> - </span>
-          ${this.renderMovedLineAnchor(range.end, otherSide)}
-        </div>
-      `;
-    }
-
-    return html`
-      <div class=${diffClasses()}>
-        <span class=${diffClasses()}
-          >${movedIn ? 'Moved in' : 'Moved out'}</span
-        >
-      </div>
-    `;
-  }
-
-  private renderMovedLineAnchor(line: number, side: Side) {
-    const listener = (e: MouseEvent) => {
-      e.preventDefault();
-      this.handleMovedLineAnchorClick(e.target, side, line);
-    };
-    // `href` is not actually used but important for Screen Readers
-    return html`
-      <a class=${diffClasses()} href=${`#${line}`} @click=${listener}
-        >${line}</a
-      >
-    `;
-  }
-
-  private handleMovedLineAnchorClick(
-    anchor: EventTarget | null,
-    side: Side,
-    line: number
-  ) {
-    if (!anchor) return;
-    fire(anchor, 'moved-link-clicked', {
-      lineNum: line,
-      side,
-    });
-  }
-}
-
-if (!isNewDiff()) {
-  customElements.define('gr-diff-section', GrDiffSection);
-}
-
-declare global {
-  interface HTMLElementTagNameMap {
-    'gr-diff-section': LitElement;
-  }
-}
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-section_test.ts b/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-section_test.ts
deleted file mode 100644
index 381f9b2..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-section_test.ts
+++ /dev/null
@@ -1,315 +0,0 @@
-/**
- * @license
- * Copyright 2022 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import '../../../test/common-test-setup';
-import './gr-diff-section';
-import {GrDiffSection} from './gr-diff-section';
-import {fixture, html, assert} from '@open-wc/testing';
-import {GrDiffGroup, GrDiffGroupType} from '../gr-diff/gr-diff-group';
-import {GrDiffLine} from '../gr-diff/gr-diff-line';
-import {DiffViewMode, GrDiffLineType} from '../../../api/diff';
-import {waitQueryAndAssert} from '../../../test/test-utils';
-
-suite('gr-diff-section test', () => {
-  let element: GrDiffSection;
-
-  setup(async () => {
-    element = await fixture<GrDiffSection>(
-      html`<gr-diff-section></gr-diff-section>`
-    );
-    element.addTableWrapperForTesting = true;
-    await element.updateComplete;
-  });
-
-  suite('move controls', async () => {
-    setup(async () => {
-      const lines = [new GrDiffLine(GrDiffLineType.BOTH, 1, 1)];
-      lines[0].text = 'asdf';
-      const group = new GrDiffGroup({
-        type: GrDiffGroupType.BOTH,
-        lines,
-        moveDetails: {changed: false, range: {start: 1, end: 2}},
-      });
-      element.group = group;
-      await element.updateComplete;
-    });
-
-    test('side-by-side', async () => {
-      const row = await waitQueryAndAssert(element, 'tr.moveControls');
-      // Semantic dom diff has a problem with just comparing table rows or
-      // cells directly. So as a workaround put the row into an empty test
-      // table.
-      const testTable = document.createElement('table');
-      testTable.appendChild(row);
-      assert.dom.equal(
-        testTable,
-        /* HTML */ `
-          <table>
-            <tbody>
-              <tr class="gr-diff moveControls movedOut">
-                <td class="gr-diff moveControlsLineNumCol"></td>
-                <td class="gr-diff sign"></td>
-                <td class="gr-diff moveHeader">
-                  <gr-range-header class="gr-diff" icon="move_item">
-                    <div class="gr-diff">
-                      <span class="gr-diff"> Moved to lines </span>
-                      <a class="gr-diff" href="#1"> 1 </a>
-                      <span class="gr-diff"> - </span>
-                      <a class="gr-diff" href="#2"> 2 </a>
-                    </div>
-                  </gr-range-header>
-                </td>
-                <td class="gr-diff moveControlsLineNumCol"></td>
-                <td class="gr-diff sign"></td>
-                <td class="gr-diff"></td>
-              </tr>
-            </tbody>
-          </table>
-        `,
-        {}
-      );
-    });
-
-    test('unified', async () => {
-      element.renderPrefs = {
-        ...element.renderPrefs,
-        view_mode: DiffViewMode.UNIFIED,
-      };
-      const row = await waitQueryAndAssert(element, 'tr.moveControls');
-      // Semantic dom diff has a problem with just comparing table rows or
-      // cells directly. So as a workaround put the row into an empty test
-      // table.
-      const testTable = document.createElement('table');
-      testTable.appendChild(row);
-      assert.dom.equal(
-        testTable,
-        /* HTML */ `
-          <table>
-            <tbody>
-              <tr class="gr-diff moveControls movedOut">
-                <td class="gr-diff moveControlsLineNumCol"></td>
-                <td class="gr-diff moveControlsLineNumCol"></td>
-                <td class="gr-diff moveHeader">
-                  <gr-range-header class="gr-diff" icon="move_item">
-                    <div class="gr-diff">
-                      <span class="gr-diff"> Moved to lines </span>
-                      <a class="gr-diff" href="#1"> 1 </a>
-                      <span class="gr-diff"> - </span>
-                      <a class="gr-diff" href="#2"> 2 </a>
-                    </div>
-                  </gr-range-header>
-                </td>
-              </tr>
-            </tbody>
-          </table>
-        `,
-        {}
-      );
-    });
-  });
-
-  test('3 normal unchanged rows', async () => {
-    const lines = [
-      new GrDiffLine(GrDiffLineType.BOTH, 1, 1),
-      new GrDiffLine(GrDiffLineType.BOTH, 1, 1),
-      new GrDiffLine(GrDiffLineType.BOTH, 1, 1),
-    ];
-    lines[0].text = 'asdf';
-    lines[1].text = 'qwer';
-    lines[2].text = 'zxcv';
-    const group = new GrDiffGroup({type: GrDiffGroupType.BOTH, lines});
-    element.group = group;
-    await element.updateComplete;
-    assert.lightDom.equal(
-      element,
-      /* HTML */ `
-        <gr-diff-row class="left-1 right-1"> </gr-diff-row>
-        <slot name="post-left-line-1"></slot>
-        <slot name="post-right-line-1"></slot>
-        <gr-diff-row class="left-1 right-1"> </gr-diff-row>
-        <slot name="post-left-line-1"></slot>
-        <slot name="post-right-line-1"></slot>
-        <gr-diff-row class="left-1 right-1"> </gr-diff-row>
-        <slot name="post-left-line-1"></slot>
-        <slot name="post-right-line-1"></slot>
-        <table>
-          <tbody class="both gr-diff section">
-            <tr
-              aria-labelledby="left-button-1 left-content-1 right-button-1 right-content-1"
-              class="diff-row gr-diff side-by-side"
-              left-type="both"
-              right-type="both"
-              tabindex="-1"
-            >
-              <td class="blame gr-diff" data-line-number="1"></td>
-              <td class="gr-diff left lineNum" data-value="1">
-                <button
-                  aria-label="1 unmodified"
-                  class="gr-diff left lineNumButton"
-                  data-value="1"
-                  id="left-button-1"
-                  tabindex="-1"
-                >
-                  1
-                </button>
-              </td>
-              <td class="gr-diff left no-intraline-info sign"></td>
-              <td class="both content gr-diff left no-intraline-info">
-                <div
-                  class="contentText gr-diff"
-                  data-side="left"
-                  id="left-content-1"
-                >
-                  <gr-diff-text> </gr-diff-text>
-                </div>
-                <div class="thread-group" data-side="left">
-                  <slot name="left-1"> </slot>
-                </div>
-              </td>
-              <td class="gr-diff lineNum right" data-value="1">
-                <button
-                  aria-label="1 unmodified"
-                  class="gr-diff lineNumButton right"
-                  data-value="1"
-                  id="right-button-1"
-                  tabindex="-1"
-                >
-                  1
-                </button>
-              </td>
-              <td class="gr-diff no-intraline-info right sign"></td>
-              <td class="both content gr-diff no-intraline-info right">
-                <div
-                  class="contentText gr-diff"
-                  data-side="right"
-                  id="right-content-1"
-                >
-                  <gr-diff-text> </gr-diff-text>
-                </div>
-                <div class="thread-group" data-side="right">
-                  <slot name="right-1"> </slot>
-                </div>
-              </td>
-            </tr>
-            <tr
-              aria-labelledby="left-button-1 left-content-1 right-button-1 right-content-1"
-              class="diff-row gr-diff side-by-side"
-              left-type="both"
-              right-type="both"
-              tabindex="-1"
-            >
-              <td class="blame gr-diff" data-line-number="1"></td>
-              <td class="gr-diff left lineNum" data-value="1">
-                <button
-                  aria-label="1 unmodified"
-                  class="gr-diff left lineNumButton"
-                  data-value="1"
-                  id="left-button-1"
-                  tabindex="-1"
-                >
-                  1
-                </button>
-              </td>
-              <td class="gr-diff left no-intraline-info sign"></td>
-              <td class="both content gr-diff left no-intraline-info">
-                <div
-                  class="contentText gr-diff"
-                  data-side="left"
-                  id="left-content-1"
-                >
-                  <gr-diff-text> </gr-diff-text>
-                </div>
-                <div class="thread-group" data-side="left">
-                  <slot name="left-1"> </slot>
-                </div>
-              </td>
-              <td class="gr-diff lineNum right" data-value="1">
-                <button
-                  aria-label="1 unmodified"
-                  class="gr-diff lineNumButton right"
-                  data-value="1"
-                  id="right-button-1"
-                  tabindex="-1"
-                >
-                  1
-                </button>
-              </td>
-              <td class="gr-diff no-intraline-info right sign"></td>
-              <td class="both content gr-diff no-intraline-info right">
-                <div
-                  class="contentText gr-diff"
-                  data-side="right"
-                  id="right-content-1"
-                >
-                  <gr-diff-text> </gr-diff-text>
-                </div>
-                <div class="thread-group" data-side="right">
-                  <slot name="right-1"> </slot>
-                </div>
-              </td>
-            </tr>
-            <tr
-              aria-labelledby="left-button-1 left-content-1 right-button-1 right-content-1"
-              class="diff-row gr-diff side-by-side"
-              left-type="both"
-              right-type="both"
-              tabindex="-1"
-            >
-              <td class="blame gr-diff" data-line-number="1"></td>
-              <td class="gr-diff left lineNum" data-value="1">
-                <button
-                  aria-label="1 unmodified"
-                  class="gr-diff left lineNumButton"
-                  data-value="1"
-                  id="left-button-1"
-                  tabindex="-1"
-                >
-                  1
-                </button>
-              </td>
-              <td class="gr-diff left no-intraline-info sign"></td>
-              <td class="both content gr-diff left no-intraline-info">
-                <div
-                  class="contentText gr-diff"
-                  data-side="left"
-                  id="left-content-1"
-                >
-                  <gr-diff-text> </gr-diff-text>
-                </div>
-                <div class="thread-group" data-side="left">
-                  <slot name="left-1"> </slot>
-                </div>
-              </td>
-              <td class="gr-diff lineNum right" data-value="1">
-                <button
-                  aria-label="1 unmodified"
-                  class="gr-diff lineNumButton right"
-                  data-value="1"
-                  id="right-button-1"
-                  tabindex="-1"
-                >
-                  1
-                </button>
-              </td>
-              <td class="gr-diff no-intraline-info right sign"></td>
-              <td class="both content gr-diff no-intraline-info right">
-                <div
-                  class="contentText gr-diff"
-                  data-side="right"
-                  id="right-content-1"
-                >
-                  <gr-diff-text> </gr-diff-text>
-                </div>
-                <div class="thread-group" data-side="right">
-                  <slot name="right-1"> </slot>
-                </div>
-              </td>
-            </tr>
-          </tbody>
-        </table>
-      `
-    );
-  });
-});
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-text.ts b/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-text.ts
deleted file mode 100644
index 3878402..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-text.ts
+++ /dev/null
@@ -1,155 +0,0 @@
-/**
- * @license
- * Copyright 2022 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import {LitElement, html, TemplateResult} from 'lit';
-import {property} from 'lit/decorators.js';
-import {styleMap} from 'lit/directives/style-map.js';
-import {diffClasses, isNewDiff} from '../../diff/gr-diff/gr-diff-utils';
-
-const SURROGATE_PAIR = /[\uD800-\uDBFF][\uDC00-\uDFFF]/;
-
-const TAB = '\t';
-
-/**
- * Renders one line of code on one side of the diff. It takes care of:
- * - Tabs, see `tabSize` property.
- * - Line Breaks, see `lineLimit` property.
- * - Surrogate Character Pairs.
- *
- * Note that other modifications to the code in a gr-diff is done via diff
- * layers, which manipulate the DOM directly. So `gr-diff-text` is thrown
- * away and re-rendered every time something changes by its parent
- * `gr-diff-row`. So don't bother to optimize this component for re-rendering
- * performance. And be aware that building longer lived local state is not
- * useful here.
- */
-export class GrDiffText extends LitElement {
-  /**
-   * The browser API for handling selection does not (yet) work for selection
-   * across multiple shadow DOM elements. So we are rendering gr-diff components
-   * into the light DOM instead of the shadow DOM by overriding this method,
-   * which was the recommended workaround by the lit team.
-   * See also https://github.com/WICG/webcomponents/issues/79.
-   */
-  override createRenderRoot() {
-    return this;
-  }
-
-  @property({type: String})
-  text = '';
-
-  @property({type: Boolean})
-  isResponsive = false;
-
-  @property({type: Number})
-  tabSize = 2;
-
-  @property({type: Number})
-  lineLimit = 80;
-
-  /** Temporary state while rendering. */
-  private textOffset = 0;
-
-  /** Temporary state while rendering. */
-  private columnPos = 0;
-
-  /** Temporary state while rendering. */
-  private pieces: (string | TemplateResult)[] = [];
-
-  /** Split up the string into tabs, surrogate pairs and regular segments. */
-  override render() {
-    this.textOffset = 0;
-    this.columnPos = 0;
-    this.pieces = [];
-    const splitByTab = this.text.split('\t');
-    for (let i = 0; i < splitByTab.length; i++) {
-      const splitBySurrogate = splitByTab[i].split(SURROGATE_PAIR);
-      for (let j = 0; j < splitBySurrogate.length; j++) {
-        this.renderSegment(splitBySurrogate[j]);
-        if (j < splitBySurrogate.length - 1) {
-          this.renderSurrogatePair();
-        }
-      }
-      if (i < splitByTab.length - 1) {
-        this.renderTab();
-      }
-    }
-    if (this.textOffset !== this.text.length) throw new Error('unfinished');
-    return this.pieces;
-  }
-
-  /** Render regular characters, but insert line breaks appropriately. */
-  private renderSegment(segment: string) {
-    let segmentOffset = 0;
-    while (segmentOffset < segment.length) {
-      const newOffset = Math.min(
-        segment.length,
-        segmentOffset + this.lineLimit - this.columnPos
-      );
-      this.renderString(segment.substring(segmentOffset, newOffset));
-      segmentOffset = newOffset;
-      if (segmentOffset < segment.length && this.columnPos === this.lineLimit) {
-        this.renderLineBreak();
-      }
-    }
-  }
-
-  /** Render regular characters. */
-  private renderString(s: string) {
-    if (s.length === 0) return;
-    this.pieces.push(s);
-    this.textOffset += s.length;
-    this.columnPos += s.length;
-    if (this.columnPos > this.lineLimit) throw new Error('over line limit');
-  }
-
-  /** Render a tab character. */
-  private renderTab() {
-    let tabSize = this.tabSize - (this.columnPos % this.tabSize);
-    if (this.columnPos + tabSize > this.lineLimit) {
-      this.renderLineBreak();
-      tabSize = this.tabSize;
-    }
-    const piece = html`<span
-      class=${diffClasses('tab')}
-      style=${styleMap({'tab-size': `${tabSize}`})}
-      >${TAB}</span
-    >`;
-    this.pieces.push(piece);
-    this.textOffset += 1;
-    this.columnPos += tabSize;
-  }
-
-  /** Render a surrogate pair: string length is 2, but is just 1 char. */
-  private renderSurrogatePair() {
-    if (this.columnPos === this.lineLimit) {
-      this.renderLineBreak();
-    }
-    this.pieces.push(this.text.substring(this.textOffset, this.textOffset + 2));
-    this.textOffset += 2;
-    this.columnPos += 1;
-  }
-
-  /** Render a line break, don't advance text offset, reset col position. */
-  private renderLineBreak() {
-    if (this.isResponsive) {
-      this.pieces.push(html`<wbr class=${diffClasses()}></wbr>`);
-    } else {
-      this.pieces.push(html`<span class=${diffClasses('br')}></span>`);
-    }
-    // this.textOffset += 0;
-    this.columnPos = 0;
-  }
-}
-
-if (!isNewDiff()) {
-  customElements.define('gr-diff-text', GrDiffText);
-}
-
-declare global {
-  interface HTMLElementTagNameMap {
-    'gr-diff-text': LitElement;
-  }
-}
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-text_test.ts b/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-text_test.ts
deleted file mode 100644
index 3858bed..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff-builder/gr-diff-text_test.ts
+++ /dev/null
@@ -1,166 +0,0 @@
-/**
- * @license
- * Copyright 2022 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import '../../../test/common-test-setup';
-import './gr-diff-text';
-import {GrDiffText} from './gr-diff-text';
-import {fixture, html, assert} from '@open-wc/testing';
-
-const LINE_BREAK = '<span class="gr-diff br"></span>';
-
-const LINE_BREAK_WBR = '<wbr class="gr-diff"></wbr>';
-
-const TAB = '<span class="" style=""></span>';
-
-const TAB_IGNORE = ['class', 'style'];
-
-suite('gr-diff-text test', () => {
-  let element: GrDiffText;
-
-  setup(async () => {
-    element = await fixture<GrDiffText>(
-      html`<gr-diff-text tabsize="4" linelimit="10"></gr-diff-text>`
-    );
-  });
-
-  const check = async (
-    text: string,
-    html: string,
-    ignoreAttributes: string[] = []
-  ) => {
-    element.text = text;
-    await element.updateComplete;
-    assert.lightDom.equal(element, html, {ignoreAttributes});
-  };
-
-  suite('lit rendering', () => {
-    test('renderText newlines 1', async () => {
-      await check('abcdef', 'abcdef');
-      await check('a'.repeat(20), `aaaaaaaaaa${LINE_BREAK}aaaaaaaaaa`);
-    });
-
-    test('renderText newlines 1 responsive', async () => {
-      element.isResponsive = true;
-      await check('abcdef', 'abcdef');
-      await check('a'.repeat(20), `aaaaaaaaaa${LINE_BREAK_WBR}aaaaaaaaaa`);
-    });
-
-    test('renderText newlines 2', async () => {
-      await check(
-        '<span class="thumbsup">👍</span>',
-        '&lt;span clas' +
-          LINE_BREAK +
-          's="thumbsu' +
-          LINE_BREAK +
-          'p"&gt;👍&lt;/span' +
-          LINE_BREAK +
-          '&gt;'
-      );
-    });
-
-    test('renderText newlines 3', async () => {
-      await check(
-        '01234\t56789',
-        '01234' + TAB + '56' + LINE_BREAK + '789',
-        TAB_IGNORE
-      );
-    });
-
-    test('renderText newlines 4', async () => {
-      element.lineLimit = 20;
-      await element.updateComplete;
-      await check(
-        '👍'.repeat(58),
-        '👍'.repeat(20) +
-          LINE_BREAK +
-          '👍'.repeat(20) +
-          LINE_BREAK +
-          '👍'.repeat(18)
-      );
-    });
-
-    test('tab wrapper style', async () => {
-      element.lineLimit = 100;
-      element.tabSize = 4;
-      await check(
-        '\t',
-        /* HTML */ '<span class="gr-diff tab" style="tab-size:4;"></span>'
-      );
-      await check(
-        'abc\t',
-        /* HTML */ 'abc<span class="gr-diff tab" style="tab-size:1;"></span>'
-      );
-
-      element.tabSize = 8;
-      await check(
-        '\t',
-        /* HTML */ '<span class="gr-diff tab" style="tab-size:8;"></span>'
-      );
-      await check(
-        'abc\t',
-        /* HTML */ 'abc<span class="gr-diff tab" style="tab-size:5;"></span>'
-      );
-    });
-
-    test('tab wrapper insertion', async () => {
-      await check('abc\tdef', 'abc' + TAB + 'def', TAB_IGNORE);
-    });
-
-    test('escaping HTML', async () => {
-      element.lineLimit = 100;
-      await element.updateComplete;
-      await check(
-        '<script>alert("XSS");<' + '/script>',
-        '&lt;script&gt;alert("XSS");&lt;/script&gt;'
-      );
-      await check('& < > " \' / `', '&amp; &lt; &gt; " \' / `');
-    });
-
-    test('text length with tabs and unicode', async () => {
-      async function expectTextLength(
-        text: string,
-        tabSize: number,
-        expected: number
-      ) {
-        element.text = text;
-        element.tabSize = tabSize;
-        element.lineLimit = expected;
-        await element.updateComplete;
-        const result = element.innerHTML;
-
-        // Must not contain a line break.
-        assert.isNotOk(element.querySelector('span.br'));
-
-        // Increasing the line limit by 1 should not change anything.
-        element.lineLimit = expected + 1;
-        await element.updateComplete;
-        const resultPlusOne = element.innerHTML;
-        assert.equal(resultPlusOne, result);
-
-        // Increasing the line limit to infinity should not change anything.
-        element.lineLimit = Infinity;
-        await element.updateComplete;
-        const resultInf = element.innerHTML;
-        assert.equal(resultInf, result);
-
-        // Decreasing the line limit by 1 should introduce a line break.
-        element.lineLimit = expected + 1;
-        await element.updateComplete;
-        assert.isNotOk(element.querySelector('span.br'));
-      }
-      expectTextLength('12345', 4, 5);
-      expectTextLength('\t\t12', 4, 10);
-      expectTextLength('abc💢123', 4, 7);
-      expectTextLength('abc\t', 8, 8);
-      expectTextLength('abc\t\t', 10, 20);
-      expectTextLength('', 10, 0);
-      // 17 Thai combining chars.
-      expectTextLength('ก้้้้้้้้้้้้้้้้', 4, 17);
-      expectTextLength('abc\tde', 10, 12);
-      expectTextLength('abc\tde\t', 10, 20);
-      expectTextLength('\t\t\t\t\t', 20, 100);
-    });
-  });
-});
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff-cursor/gr-diff-cursor.ts b/polygerrit-ui/app/embed/diff-old/gr-diff-cursor/gr-diff-cursor.ts
deleted file mode 100644
index 3d0e507..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff-cursor/gr-diff-cursor.ts
+++ /dev/null
@@ -1,597 +0,0 @@
-/**
- * @license
- * Copyright 2016 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import {Subscription} from 'rxjs';
-import {AbortStop, CursorMoveResult, Stop} from '../../../api/core';
-import {
-  DiffViewMode,
-  GrDiffCursor as GrDiffCursorApi,
-  GrDiffLineType,
-  LineNumber,
-  LineSelectedEventDetail,
-} from '../../../api/diff';
-import {ScrollMode, Side} from '../../../constants/constants';
-import {toggleClass} from '../../../utils/dom-util';
-import {
-  GrCursorManager,
-  isTargetable,
-} from '../../../elements/shared/gr-cursor-manager/gr-cursor-manager';
-import {GrDiffGroupType} from '../gr-diff/gr-diff-group';
-import {GrDiff} from '../gr-diff/gr-diff';
-import {fire} from '../../../utils/event-util';
-
-type GrDiffRowType = GrDiffLineType | GrDiffGroupType;
-
-const LEFT_SIDE_CLASS = 'target-side-left';
-const RIGHT_SIDE_CLASS = 'target-side-right';
-
-interface Address {
-  leftSide: boolean;
-  number: number;
-}
-
-/**
- * From <tr> diff row go up to <tbody> diff chunk.
- *
- * In Lit based diff there is a <gr-diff-row> element in between the two.
- */
-export function fromRowToChunk(
-  rowEl: HTMLElement
-): HTMLTableSectionElement | undefined {
-  const parent = rowEl.parentElement;
-  if (!parent) return undefined;
-  if (parent.tagName === 'TBODY') {
-    return parent as HTMLTableSectionElement;
-  }
-
-  const grandParent = parent.parentElement;
-  if (!grandParent) return undefined;
-  if (grandParent.tagName === 'TBODY') {
-    return grandParent as HTMLTableSectionElement;
-  }
-
-  return undefined;
-}
-
-/** A subset of the GrDiff API that the cursor is using. */
-export interface GrDiffCursorable extends HTMLElement {
-  isRangeSelected(): boolean;
-  createRangeComment(): void;
-  getCursorStops(): Stop[];
-  path?: string;
-}
-
-export class GrDiffCursor implements GrDiffCursorApi {
-  private preventAutoScrollOnManualScroll = false;
-
-  set side(side: Side) {
-    if (this.sideInternal === side) {
-      return;
-    }
-    if (this.sideInternal && this.diffRow) {
-      this.fireCursorMoved(
-        'line-cursor-moved-out',
-        this.diffRow,
-        this.sideInternal
-      );
-    }
-    this.sideInternal = side;
-    this.updateSideClass();
-    if (this.diffRow) {
-      this.fireCursorMoved('line-cursor-moved-in', this.diffRow, this.side);
-    }
-  }
-
-  get side(): Side {
-    return this.sideInternal;
-  }
-
-  private sideInternal = Side.RIGHT;
-
-  set diffRow(diffRow: HTMLElement | undefined) {
-    if (this.diffRowInternal) {
-      this.diffRowInternal.classList.remove(LEFT_SIDE_CLASS, RIGHT_SIDE_CLASS);
-      this.fireCursorMoved(
-        'line-cursor-moved-out',
-        this.diffRowInternal,
-        this.side
-      );
-    }
-    this.diffRowInternal = diffRow;
-
-    this.updateSideClass();
-    if (this.diffRow) {
-      this.fireCursorMoved('line-cursor-moved-in', this.diffRow, this.side);
-    }
-  }
-
-  get diffRow(): HTMLElement | undefined {
-    return this.diffRowInternal;
-  }
-
-  private diffRowInternal?: HTMLElement;
-
-  private diffs: GrDiffCursorable[] = [];
-
-  /**
-   * If set, the cursor will attempt to move to the line number (instead of
-   * the first chunk) the next time the diff renders. It is set back to null
-   * when used. It should be only used if you want the line to be focused
-   * after initialization of the component and page should scroll
-   * to that position. This parameter should be set at most for one gr-diff
-   * element in the page.
-   */
-  initialLineNumber: number | null = null;
-
-  // visible for testing
-  cursorManager = new GrCursorManager();
-
-  private targetSubscription?: Subscription;
-
-  constructor() {
-    this.cursorManager.cursorTargetClass = 'target-row';
-    this.cursorManager.scrollMode = ScrollMode.KEEP_VISIBLE;
-    this.cursorManager.focusOnMove = true;
-
-    window.addEventListener('scroll', this._boundHandleWindowScroll);
-    this.targetSubscription = this.cursorManager.target$.subscribe(target => {
-      this.diffRow = target || undefined;
-    });
-  }
-
-  dispose() {
-    this.cursorManager.unsetCursor();
-    if (this.targetSubscription) this.targetSubscription.unsubscribe();
-    window.removeEventListener('scroll', this._boundHandleWindowScroll);
-  }
-
-  // Don't remove - used by clients embedding gr-diff outside of Gerrit.
-  isAtStart() {
-    return this.cursorManager.isAtStart();
-  }
-
-  // Don't remove - used by clients embedding gr-diff outside of Gerrit.
-  isAtEnd() {
-    return this.cursorManager.isAtEnd();
-  }
-
-  moveLeft() {
-    this.side = Side.LEFT;
-    if (this._isTargetBlank()) {
-      this.moveUp();
-    }
-  }
-
-  moveRight() {
-    this.side = Side.RIGHT;
-    if (this._isTargetBlank()) {
-      this.moveUp();
-    }
-  }
-
-  moveDown() {
-    if (this._getViewMode() === DiffViewMode.SIDE_BY_SIDE) {
-      return this.cursorManager.next({
-        filter: (row: Element) => this._rowHasSide(row),
-      });
-    } else {
-      return this.cursorManager.next();
-    }
-  }
-
-  moveUp() {
-    if (this._getViewMode() === DiffViewMode.SIDE_BY_SIDE) {
-      return this.cursorManager.previous({
-        filter: (row: Element) => this._rowHasSide(row),
-      });
-    } else {
-      return this.cursorManager.previous();
-    }
-  }
-
-  moveToVisibleArea() {
-    if (this._getViewMode() === DiffViewMode.SIDE_BY_SIDE) {
-      this.cursorManager.moveToVisibleArea((row: Element) =>
-        this._rowHasSide(row)
-      );
-    } else {
-      this.cursorManager.moveToVisibleArea();
-    }
-  }
-
-  moveToNextChunk(clipToTop?: boolean): CursorMoveResult {
-    const result = this.cursorManager.next({
-      filter: (row: HTMLElement) => this._isFirstRowOfChunk(row),
-      getTargetHeight: target => fromRowToChunk(target)?.scrollHeight || 0,
-      clipToTop,
-    });
-    this._fixSide();
-    return result;
-  }
-
-  moveToPreviousChunk(): CursorMoveResult {
-    const result = this.cursorManager.previous({
-      filter: (row: HTMLElement) => this._isFirstRowOfChunk(row),
-    });
-    this._fixSide();
-    return result;
-  }
-
-  moveToNextCommentThread(): CursorMoveResult {
-    if (this.isAtEnd()) {
-      return CursorMoveResult.CLIPPED;
-    }
-    const result = this.cursorManager.next({
-      filter: (row: HTMLElement) => this._rowHasThread(row),
-    });
-    this._fixSide();
-    return result;
-  }
-
-  moveToPreviousCommentThread(): CursorMoveResult {
-    const result = this.cursorManager.previous({
-      filter: (row: HTMLElement) => this._rowHasThread(row),
-    });
-    this._fixSide();
-    return result;
-  }
-
-  moveToLineNumber(
-    number: LineNumber,
-    side: Side,
-    path?: string,
-    intentionalMove?: boolean
-  ) {
-    const row = this._findRowByNumberAndFile(number, side, path);
-    if (row) {
-      this.side = side;
-      this.cursorManager.setCursor(row, undefined, intentionalMove);
-    }
-  }
-
-  /**
-   * Get the line number element targeted by the cursor row and side.
-   */
-  getTargetLineElement(): HTMLElement | null {
-    let lineElSelector = '.lineNum';
-
-    if (!this.diffRow) {
-      return null;
-    }
-
-    if (this._getViewMode() === DiffViewMode.SIDE_BY_SIDE) {
-      lineElSelector += this.side === Side.LEFT ? '.left' : '.right';
-    }
-
-    return this.diffRow.querySelector(lineElSelector);
-  }
-
-  getTargetDiffElement(): GrDiff | null {
-    if (!this.diffRow) return null;
-
-    const hostOwner = this.diffRow.getRootNode() as ShadowRoot;
-    if (hostOwner?.host?.tagName === 'GR-DIFF') {
-      return hostOwner.host as GrDiff;
-    }
-    return null;
-  }
-
-  moveToFirstChunk() {
-    this.cursorManager.moveToStart();
-    if (this.diffRow && !this._isFirstRowOfChunk(this.diffRow)) {
-      this.moveToNextChunk(true);
-    } else {
-      this._fixSide();
-    }
-  }
-
-  moveToLastChunk() {
-    this.cursorManager.moveToEnd();
-    if (this.diffRow && !this._isFirstRowOfChunk(this.diffRow)) {
-      this.moveToPreviousChunk();
-    } else {
-      this._fixSide();
-    }
-  }
-
-  /**
-   * Move the cursor either to initialLineNumber or the first chunk and
-   * reset scroll behavior.
-   *
-   * This may grab the focus from the app.
-   *
-   * If you do not want to move the cursor or grab focus, and just want to
-   * reset the scroll behavior, use reInitAndUpdateStops() instead.
-   */
-  reInitCursor() {
-    this._updateStops();
-    if (!this.diffRow) {
-      // does not scroll during init unless requested
-      this.cursorManager.scrollMode = this.initialLineNumber
-        ? ScrollMode.KEEP_VISIBLE
-        : ScrollMode.NEVER;
-      if (this.initialLineNumber) {
-        this.moveToLineNumber(this.initialLineNumber, this.side);
-        this.initialLineNumber = null;
-      } else {
-        this.moveToFirstChunk();
-      }
-    }
-    this.resetScrollMode();
-  }
-
-  resetScrollMode() {
-    this.cursorManager.scrollMode = ScrollMode.KEEP_VISIBLE;
-  }
-
-  private _boundHandleWindowScroll = () => {
-    if (this.preventAutoScrollOnManualScroll) {
-      this.cursorManager.scrollMode = ScrollMode.NEVER;
-      this.cursorManager.focusOnMove = false;
-      this.preventAutoScrollOnManualScroll = false;
-    }
-  };
-
-  reInitAndUpdateStops() {
-    this.resetScrollMode();
-    this._updateStops();
-  }
-
-  private boundHandleDiffLoadingChanged = () => {
-    this._updateStops();
-  };
-
-  private _boundHandleDiffRenderStart = () => {
-    this.preventAutoScrollOnManualScroll = true;
-  };
-
-  private _boundHandleDiffRenderContent = () => {
-    this._updateStops();
-    // When done rendering, turn focus on move and automatic scrolling back on
-    this.cursorManager.focusOnMove = true;
-    this.preventAutoScrollOnManualScroll = false;
-  };
-
-  private _boundHandleDiffLineSelected = (
-    e: CustomEvent<LineSelectedEventDetail>
-  ) => {
-    this.moveToLineNumber(e.detail.number, e.detail.side, e.detail.path);
-  };
-
-  createCommentInPlace() {
-    const diffWithRangeSelected = this.diffs.find(diff =>
-      diff.isRangeSelected()
-    );
-    if (diffWithRangeSelected) {
-      diffWithRangeSelected.createRangeComment();
-    } else {
-      const line = this.getTargetLineElement();
-      const diff = this.getTargetDiffElement();
-      if (diff && line) {
-        diff.addDraftAtLine(line);
-      }
-    }
-  }
-
-  getTargetLineNumber(): LineNumber | undefined {
-    return this.getAddress()?.number;
-  }
-
-  /**
-   * Get an object describing the location of the cursor. Such as
-   * {leftSide: false, number: 123} for line 123 of the revision, or
-   * {leftSide: true, number: 321} for line 321 of the base patch.
-   * Returns null if an address is not available.
-   */
-  getAddress(): Address | null {
-    if (!this.diffRow) {
-      return null;
-    }
-    // Get the line-number cell targeted by the cursor. If the mode is unified
-    // then prefer the revision cell if available.
-    return this.getAddressFor(this.diffRow, this.side);
-  }
-
-  private getAddressFor(diffRow: HTMLElement, side: Side): Address | null {
-    let cell;
-    if (this._getViewMode() === DiffViewMode.UNIFIED) {
-      cell = diffRow.querySelector('.lineNum.right');
-      if (!cell) {
-        cell = diffRow.querySelector('.lineNum.left');
-      }
-    } else {
-      cell = diffRow.querySelector('.lineNum.' + side);
-    }
-    if (!cell) {
-      return null;
-    }
-
-    const number = cell.getAttribute('data-value');
-    if (!number || number === 'FILE') {
-      return null;
-    }
-
-    return {
-      leftSide: cell.matches('.left'),
-      number: Number(number),
-    };
-  }
-
-  _getViewMode() {
-    if (!this.diffRow) {
-      return null;
-    }
-
-    if (this.diffRow.classList.contains('side-by-side')) {
-      return DiffViewMode.SIDE_BY_SIDE;
-    } else {
-      return DiffViewMode.UNIFIED;
-    }
-  }
-
-  _rowHasSide(row: Element) {
-    const selector =
-      (this.side === Side.LEFT ? '.left' : '.right') + ' + .content';
-    return !!row.querySelector(selector);
-  }
-
-  _isFirstRowOfChunk(row: HTMLElement) {
-    const chunk = fromRowToChunk(row);
-    if (!chunk) return false;
-
-    const isInDeltaChunk = chunk.classList.contains('delta');
-    if (!isInDeltaChunk) return false;
-
-    const firstRow = chunk.querySelector('tr:not(.moveControls)');
-    return firstRow === row;
-  }
-
-  _rowHasThread(row: HTMLElement): boolean {
-    const slots = [
-      ...row.querySelectorAll<HTMLSlotElement>('.thread-group > slot'),
-    ];
-    return slots.some(slot => slot.assignedElements().length > 0);
-  }
-
-  /**
-   * If we jumped to a row where there is no content on the current side then
-   * switch to the alternate side.
-   */
-  _fixSide() {
-    if (
-      this._getViewMode() === DiffViewMode.SIDE_BY_SIDE &&
-      this._isTargetBlank()
-    ) {
-      this.side = this.side === Side.LEFT ? Side.RIGHT : Side.LEFT;
-    }
-  }
-
-  _isTargetBlank() {
-    if (!this.diffRow) {
-      return false;
-    }
-
-    const actions = this._getActionsForRow();
-    return (
-      (this.side === Side.LEFT && !actions.left) ||
-      (this.side === Side.RIGHT && !actions.right)
-    );
-  }
-
-  private fireCursorMoved(
-    event: 'line-cursor-moved-out' | 'line-cursor-moved-in',
-    row: HTMLElement,
-    side: Side
-  ) {
-    const address = this.getAddressFor(row, side);
-    if (address) {
-      const {leftSide, number} = address;
-      fire(row, event, {
-        lineNum: number,
-        side: leftSide ? Side.LEFT : Side.RIGHT,
-      });
-    }
-  }
-
-  private updateSideClass() {
-    if (!this.diffRow) {
-      return;
-    }
-    toggleClass(this.diffRow, LEFT_SIDE_CLASS, this.side === Side.LEFT);
-    toggleClass(this.diffRow, RIGHT_SIDE_CLASS, this.side === Side.RIGHT);
-  }
-
-  _isActionType(type: GrDiffRowType) {
-    return (
-      type !== GrDiffLineType.BLANK && type !== GrDiffGroupType.CONTEXT_CONTROL
-    );
-  }
-
-  _getActionsForRow() {
-    const actions = {left: false, right: false};
-    if (this.diffRow) {
-      actions.left = this._isActionType(
-        this.diffRow.getAttribute('left-type') as GrDiffRowType
-      );
-      actions.right = this._isActionType(
-        this.diffRow.getAttribute('right-type') as GrDiffRowType
-      );
-    }
-    return actions;
-  }
-
-  _updateStops() {
-    this.cursorManager.stops = this.diffs.reduce(
-      (stops: Stop[], diff) => stops.concat(diff.getCursorStops()),
-      []
-    );
-  }
-
-  replaceDiffs(diffs: GrDiffCursorable[]) {
-    for (const diff of this.diffs) {
-      this.removeEventListeners(diff);
-    }
-    this.diffs = [];
-    for (const diff of diffs) {
-      this.addEventListeners(diff);
-    }
-    this.diffs.push(...diffs);
-    this._updateStops();
-  }
-
-  unregisterDiff(diff: GrDiffCursorable) {
-    // This can happen during destruction - just don't unregister then.
-    if (!this.diffs) return;
-    const i = this.diffs.indexOf(diff);
-    if (i !== -1) {
-      this.diffs.splice(i, 1);
-    }
-  }
-
-  private removeEventListeners(diff: GrDiffCursorable) {
-    diff.removeEventListener(
-      'loading-changed',
-      this.boundHandleDiffLoadingChanged
-    );
-    diff.removeEventListener('render-start', this._boundHandleDiffRenderStart);
-    diff.removeEventListener(
-      'render-content',
-      this._boundHandleDiffRenderContent
-    );
-    diff.removeEventListener(
-      'line-selected',
-      this._boundHandleDiffLineSelected
-    );
-  }
-
-  private addEventListeners(diff: GrDiffCursorable) {
-    diff.addEventListener(
-      'loading-changed',
-      this.boundHandleDiffLoadingChanged
-    );
-    diff.addEventListener('render-start', this._boundHandleDiffRenderStart);
-    diff.addEventListener('render-content', this._boundHandleDiffRenderContent);
-    diff.addEventListener('line-selected', this._boundHandleDiffLineSelected);
-  }
-
-  _findRowByNumberAndFile(
-    targetNumber: LineNumber,
-    side: Side,
-    path?: string
-  ): HTMLElement | undefined {
-    let stops: Array<HTMLElement | AbortStop>;
-    if (path) {
-      const diff = this.diffs.filter(diff => diff.path === path)[0];
-      stops = diff.getCursorStops();
-    } else {
-      stops = this.cursorManager.stops;
-    }
-    // Sadly needed for type narrowing to understand that the result is always
-    // targetable.
-    const targetableStops: HTMLElement[] = stops.filter(isTargetable);
-    const selector = `.lineNum.${side}[data-value="${targetNumber}"]`;
-    return targetableStops.find(stop => stop.querySelector(selector));
-  }
-}
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff-cursor/gr-diff-cursor_test.ts b/polygerrit-ui/app/embed/diff-old/gr-diff-cursor/gr-diff-cursor_test.ts
deleted file mode 100644
index 61f8551..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff-cursor/gr-diff-cursor_test.ts
+++ /dev/null
@@ -1,694 +0,0 @@
-/**
- * @license
- * Copyright 2016 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import '../../../test/common-test-setup';
-import '../gr-diff/gr-diff';
-import './gr-diff-cursor';
-import {fixture, html, assert} from '@open-wc/testing';
-import {
-  mockPromise,
-  queryAll,
-  queryAndAssert,
-  waitUntil,
-} from '../../../test/test-utils';
-import {createDiff} from '../../../test/test-data-generators';
-import {createDefaultDiffPrefs} from '../../../constants/constants';
-import {GrDiffCursor} from './gr-diff-cursor';
-import {waitForEventOnce} from '../../../utils/event-util';
-import {DiffInfo, DiffViewMode, Side} from '../../../api/diff';
-import {GrDiff} from '../gr-diff/gr-diff';
-import {assertIsDefined} from '../../../utils/common-util';
-
-suite('gr-diff-cursor tests', () => {
-  let cursor: GrDiffCursor;
-  let diffElement: GrDiff;
-  let diff: DiffInfo;
-
-  setup(async () => {
-    diffElement = await fixture(html`<gr-diff></gr-diff>`);
-    cursor = new GrDiffCursor();
-
-    // Register the diff with the cursor.
-    cursor.replaceDiffs([diffElement]);
-
-    diffElement.loggedIn = false;
-    diffElement.path = 'some/path.ts';
-    const promise = mockPromise();
-    const setupDone = () => {
-      cursor._updateStops();
-      cursor.moveToFirstChunk();
-      diffElement.removeEventListener('render', setupDone);
-      promise.resolve();
-    };
-    diffElement.addEventListener('render', setupDone);
-
-    diff = createDiff();
-    diffElement.prefs = createDefaultDiffPrefs();
-    diffElement.diff = diff;
-    await promise;
-  });
-
-  test('diff cursor functionality (side-by-side)', () => {
-    assert.isOk(cursor.diffRow);
-
-    const deltaRows = queryAll<HTMLTableRowElement>(
-      diffElement,
-      '.section.delta tr.diff-row'
-    );
-    assert.equal(cursor.diffRow, deltaRows[0]);
-
-    cursor.moveDown();
-
-    assert.notEqual(cursor.diffRow, deltaRows[0]);
-    assert.equal(cursor.diffRow, deltaRows[1]);
-
-    cursor.moveUp();
-
-    assert.notEqual(cursor.diffRow, deltaRows[1]);
-    assert.equal(cursor.diffRow, deltaRows[0]);
-  });
-
-  test('moveToFirstChunk', async () => {
-    const diff: DiffInfo = {
-      meta_a: {
-        name: 'lorem-ipsum.txt',
-        content_type: 'text/plain',
-        lines: 3,
-      },
-      meta_b: {
-        name: 'lorem-ipsum.txt',
-        content_type: 'text/plain',
-        lines: 3,
-      },
-      intraline_status: 'OK',
-      change_type: 'MODIFIED',
-      diff_header: [
-        'diff --git a/lorem-ipsum.txt b/lorem-ipsum.txt',
-        'index b2adcf4..554ae49 100644',
-        '--- a/lorem-ipsum.txt',
-        '+++ b/lorem-ipsum.txt',
-      ],
-      content: [
-        {b: ['new line 1']},
-        {ab: ['unchanged line']},
-        {a: ['old line 2']},
-        {ab: ['more unchanged lines']},
-      ],
-    };
-
-    diffElement.diff = diff;
-    // The file comment button, if present, is a cursor stop. Ensure
-    // moveToFirstChunk() works correctly even if the button is not shown.
-    diffElement.prefs!.show_file_comment_button = false;
-    await waitForEventOnce(diffElement, 'render');
-
-    cursor._updateStops();
-
-    const chunks = [
-      ...queryAll(diffElement, '.section.delta'),
-    ] as HTMLElement[];
-    assert.equal(chunks.length, 2);
-
-    const rows = [
-      ...queryAll(diffElement, '.section.delta tr.diff-row'),
-    ] as HTMLTableRowElement[];
-    assert.equal(rows.length, 2);
-
-    // Verify it works on fresh diff.
-    cursor.moveToFirstChunk();
-    assert.ok(cursor.diffRow);
-    assert.equal(cursor.diffRow, rows[0]);
-    assert.equal(cursor.side, Side.RIGHT);
-
-    // Verify it works from other cursor positions.
-    cursor.moveToNextChunk();
-    assert.ok(cursor.diffRow);
-    assert.equal(cursor.diffRow, rows[1]);
-    assert.equal(cursor.side, Side.LEFT);
-
-    cursor.moveToFirstChunk();
-    assert.ok(cursor.diffRow);
-    assert.equal(cursor.diffRow, rows[0]);
-    assert.equal(cursor.side, Side.RIGHT);
-  });
-
-  test('moveToLastChunk', async () => {
-    const diff: DiffInfo = {
-      meta_a: {
-        name: 'lorem-ipsum.txt',
-        content_type: 'text/plain',
-        lines: 3,
-      },
-      meta_b: {
-        name: 'lorem-ipsum.txt',
-        content_type: 'text/plain',
-        lines: 3,
-      },
-      intraline_status: 'OK',
-      change_type: 'MODIFIED',
-      diff_header: [
-        'diff --git a/lorem-ipsum.txt b/lorem-ipsum.txt',
-        'index b2adcf4..554ae49 100644',
-        '--- a/lorem-ipsum.txt',
-        '+++ b/lorem-ipsum.txt',
-      ],
-      content: [
-        {ab: ['unchanged line']},
-        {a: ['old line 2']},
-        {ab: ['more unchanged lines']},
-        {b: ['new line 3']},
-      ],
-    };
-
-    diffElement.diff = diff;
-    await waitForEventOnce(diffElement, 'render');
-    cursor._updateStops();
-
-    const chunks = [
-      ...queryAll(diffElement, '.section.delta'),
-    ] as HTMLElement[];
-    assert.equal(chunks.length, 2);
-
-    const rows = [
-      ...queryAll(diffElement, '.section.delta tr.diff-row'),
-    ] as HTMLTableRowElement[];
-    assert.equal(rows.length, 2);
-
-    // Verify it works on fresh diff.
-    cursor.moveToLastChunk();
-    assert.ok(cursor.diffRow);
-    assert.equal(cursor.diffRow, rows[1]);
-    assert.equal(cursor.side, Side.RIGHT);
-
-    // Verify it works from other cursor positions.
-    cursor.moveToPreviousChunk();
-    assert.ok(cursor.diffRow);
-    assert.equal(cursor.diffRow, rows[0]);
-    assert.equal(cursor.side, Side.LEFT);
-
-    cursor.moveToLastChunk();
-    assert.ok(cursor.diffRow);
-    assert.equal(cursor.diffRow, rows[1]);
-    assert.equal(cursor.side, Side.RIGHT);
-  });
-
-  test('cursor scroll behavior', () => {
-    assert.equal(cursor.cursorManager.scrollMode, 'keep-visible');
-
-    diffElement.dispatchEvent(new Event('render-start'));
-    assert.isTrue(cursor.cursorManager.focusOnMove);
-
-    window.dispatchEvent(new Event('scroll'));
-    assert.equal(cursor.cursorManager.scrollMode, 'never');
-    assert.isFalse(cursor.cursorManager.focusOnMove);
-
-    diffElement.dispatchEvent(new Event('render-content'));
-    assert.isTrue(cursor.cursorManager.focusOnMove);
-
-    cursor.reInitCursor();
-    assert.equal(cursor.cursorManager.scrollMode, 'keep-visible');
-  });
-
-  test('moves to selected line', () => {
-    const moveToNumStub = sinon.stub(cursor, 'moveToLineNumber');
-
-    diffElement.dispatchEvent(
-      new CustomEvent('line-selected', {
-        detail: {number: '123', side: Side.RIGHT, path: 'some/file'},
-      })
-    );
-
-    assert.isTrue(moveToNumStub.called);
-    assert.equal(moveToNumStub.lastCall.args[0], 123);
-    assert.equal(moveToNumStub.lastCall.args[1], Side.RIGHT);
-    assert.equal(moveToNumStub.lastCall.args[2], 'some/file');
-  });
-
-  suite('unified diff', () => {
-    setup(async () => {
-      diffElement.viewMode = DiffViewMode.UNIFIED;
-      await waitForEventOnce(diffElement, 'render');
-      cursor.reInitCursor();
-    });
-
-    test('diff cursor functionality (unified)', () => {
-      assert.isOk(cursor.diffRow);
-
-      const rows = [
-        ...queryAll(diffElement, '.section.delta tr.diff-row'),
-      ] as HTMLTableRowElement[];
-      assert.equal(cursor.diffRow, rows[0]);
-
-      cursor.moveDown();
-
-      assert.notEqual(cursor.diffRow, rows[0]);
-      assert.equal(cursor.diffRow, rows[1]);
-
-      cursor.moveUp();
-
-      assert.notEqual(cursor.diffRow, rows[1]);
-      assert.equal(cursor.diffRow, rows[0]);
-    });
-  });
-
-  test('cursor side functionality', () => {
-    // The side only applies to side-by-side mode, which should be the default
-    // mode.
-    assert.equal(diffElement.viewMode, 'SIDE_BY_SIDE');
-
-    const rows = [
-      ...queryAll(diffElement, '.section tr.diff-row'),
-    ] as HTMLTableRowElement[];
-    assert.equal(rows.length, 50);
-    const deltaRows = [
-      ...queryAll(diffElement, '.section.delta tr.diff-row'),
-    ] as HTMLTableRowElement[];
-    assert.equal(deltaRows.length, 14);
-    const indexFirstDelta = rows.indexOf(deltaRows[0]);
-    const rowBeforeFirstDelta = rows[indexFirstDelta - 1];
-
-    // Because the first delta in this diff is on the right, it should be set
-    // to the right side.
-    assert.equal(cursor.side, Side.RIGHT);
-    assert.equal(cursor.diffRow, deltaRows[0]);
-    const firstIndex = cursor.cursorManager.index;
-
-    // Move the side to the left. Because this delta only has a right side, we
-    // should be moved up to the previous line where there is content on the
-    // right. The previous row is part of the previous section.
-    cursor.moveLeft();
-
-    assert.equal(cursor.side, Side.LEFT);
-    assert.notEqual(cursor.diffRow, rows[0]);
-    assert.equal(cursor.diffRow, rowBeforeFirstDelta);
-    assert.equal(cursor.cursorManager.index, firstIndex - 1);
-
-    // If we move down, we should skip everything in the first delta because
-    // we are on the left side and the first delta has no content on the left.
-    cursor.moveDown();
-
-    assert.equal(cursor.side, Side.LEFT);
-    assert.notEqual(cursor.diffRow, rowBeforeFirstDelta);
-    assert.notEqual(cursor.diffRow, rows[0]);
-    assert.isTrue(cursor.cursorManager.index > firstIndex);
-  });
-
-  test('chunk skip functionality', () => {
-    const deltaChunks = [...queryAll(diffElement, 'tbody.section.delta')];
-
-    // We should be initialized to the first chunk. Since this chunk only has
-    // content on the right side, our side should be right.
-    assert.equal(cursor.diffRow, deltaChunks[0].querySelector('tr'));
-    assert.equal(cursor.side, Side.RIGHT);
-
-    // Move to the next chunk.
-    cursor.moveToNextChunk();
-
-    // Since this chunk only has content on the left side. we should have been
-    // automatically moved over.
-    assert.equal(cursor.diffRow, deltaChunks[1].querySelector('tr'));
-    assert.equal(cursor.side, Side.LEFT);
-  });
-
-  suite('moved chunks without line range)', () => {
-    setup(async () => {
-      const promise = mockPromise();
-      const renderHandler = function () {
-        diffElement.removeEventListener('render', renderHandler);
-        cursor.reInitCursor();
-        promise.resolve();
-      };
-      diffElement.addEventListener('render', renderHandler);
-      diffElement.diff = {
-        ...diff,
-        content: [
-          {
-            ab: ['Lorem ipsum dolor sit amet, suspendisse inceptos vehicula, '],
-          },
-          {
-            b: [
-              'Nullam neque, ligula ac, id blandit.',
-              'Sagittis tincidunt torquent, tempor nunc amet.',
-              'At rhoncus id.',
-            ],
-            move_details: {changed: false},
-          },
-          {
-            ab: ['Sem nascetur, erat ut, non in.'],
-          },
-          {
-            a: [
-              'Nullam neque, ligula ac, id blandit.',
-              'Sagittis tincidunt torquent, tempor nunc amet.',
-              'At rhoncus id.',
-            ],
-            move_details: {changed: false},
-          },
-          {
-            ab: ['Arcu eget, rhoncus amet cursus, ipsum elementum.'],
-          },
-        ],
-      };
-      await promise;
-    });
-
-    test('renders moveControls with simple descriptions', () => {
-      const [movedIn, movedOut] = [
-        ...queryAll<HTMLElement>(diffElement, '.dueToMove tr.moveControls'),
-      ];
-      assert.include(movedIn.innerText, 'Moved in');
-      assert.include(movedOut.innerText, 'Moved out');
-    });
-  });
-
-  suite('moved chunks (moveDetails)', () => {
-    setup(async () => {
-      const promise = mockPromise();
-      const renderHandler = function () {
-        diffElement.removeEventListener('render', renderHandler);
-        cursor.reInitCursor();
-        promise.resolve();
-      };
-      diffElement.addEventListener('render', renderHandler);
-      diffElement.diff = {
-        ...diff,
-        content: [
-          {
-            ab: ['Lorem ipsum dolor sit amet, suspendisse inceptos vehicula, '],
-          },
-          {
-            b: [
-              'Nullam neque, ligula ac, id blandit.',
-              'Sagittis tincidunt torquent, tempor nunc amet.',
-              'At rhoncus id.',
-            ],
-            move_details: {changed: false, range: {start: 4, end: 6}},
-          },
-          {
-            ab: ['Sem nascetur, erat ut, non in.'],
-          },
-          {
-            a: [
-              'Nullam neque, ligula ac, id blandit.',
-              'Sagittis tincidunt torquent, tempor nunc amet.',
-              'At rhoncus id.',
-            ],
-            move_details: {changed: false, range: {start: 2, end: 4}},
-          },
-          {
-            ab: ['Arcu eget, rhoncus amet cursus, ipsum elementum.'],
-          },
-        ],
-      };
-      await promise;
-    });
-
-    test('renders moveControls with simple descriptions', () => {
-      const [movedIn, movedOut] = [
-        ...queryAll<HTMLElement>(diffElement, '.dueToMove tr.moveControls'),
-      ];
-      assert.include(movedIn.innerText, 'Moved from lines 4 - 6');
-      assert.include(movedOut.innerText, 'Moved to lines 2 - 4');
-    });
-
-    test('startLineAnchor of movedIn chunk fires events', async () => {
-      const [movedIn] = [...queryAll(diffElement, '.dueToMove .moveControls')];
-      const [startLineAnchor] = movedIn.querySelectorAll('a');
-
-      const promise = mockPromise();
-      const onMovedLinkClicked = (e: CustomEvent) => {
-        assert.deepEqual(e.detail, {lineNum: 4, side: Side.LEFT});
-        promise.resolve();
-      };
-      assert.equal(startLineAnchor.textContent, '4');
-      startLineAnchor.addEventListener(
-        'moved-link-clicked',
-        onMovedLinkClicked
-      );
-      startLineAnchor.click();
-      await promise;
-    });
-
-    test('endLineAnchor of movedOut fires events', async () => {
-      const [, movedOut] = [
-        ...queryAll(diffElement, '.dueToMove .moveControls'),
-      ];
-      const [, endLineAnchor] = movedOut.querySelectorAll('a');
-
-      const promise = mockPromise();
-      const onMovedLinkClicked = (e: CustomEvent) => {
-        assert.deepEqual(e.detail, {lineNum: 4, side: Side.RIGHT});
-        promise.resolve();
-      };
-      assert.equal(endLineAnchor.textContent, '4');
-      endLineAnchor.addEventListener('moved-link-clicked', onMovedLinkClicked);
-      endLineAnchor.click();
-      await promise;
-    });
-  });
-
-  test('initialLineNumber not provided', async () => {
-    let scrollBehaviorDuringMove;
-    const moveToNumStub = sinon.stub(cursor, 'moveToLineNumber');
-    const moveToChunkStub = sinon
-      .stub(cursor, 'moveToFirstChunk')
-      .callsFake(() => {
-        scrollBehaviorDuringMove = cursor.cursorManager.scrollMode;
-      });
-    diffElement.diff = createDiff();
-    await diffElement.updateComplete;
-    await waitForEventOnce(diffElement, 'render');
-    cursor.reInitCursor();
-    assert.isFalse(moveToNumStub.called);
-    assert.isTrue(moveToChunkStub.called);
-    assert.equal(scrollBehaviorDuringMove, 'never');
-    assert.equal(cursor.cursorManager.scrollMode, 'keep-visible');
-  });
-
-  test('initialLineNumber provided', async () => {
-    let scrollBehaviorDuringMove;
-    const moveToNumStub = sinon
-      .stub(cursor, 'moveToLineNumber')
-      .callsFake(() => {
-        scrollBehaviorDuringMove = cursor.cursorManager.scrollMode;
-      });
-    const moveToChunkStub = sinon.stub(cursor, 'moveToFirstChunk');
-    cursor.initialLineNumber = 10;
-    cursor.side = Side.RIGHT;
-
-    diffElement.diff = createDiff();
-    await diffElement.updateComplete;
-    await waitForEventOnce(diffElement, 'render');
-    cursor.reInitCursor();
-    assert.isFalse(moveToChunkStub.called);
-    assert.isTrue(moveToNumStub.called);
-    assert.equal(moveToNumStub.lastCall.args[0], 10);
-    assert.equal(moveToNumStub.lastCall.args[1], Side.RIGHT);
-    assert.equal(scrollBehaviorDuringMove, 'keep-visible');
-    assert.equal(cursor.cursorManager.scrollMode, 'keep-visible');
-  });
-
-  test('getTargetDiffElement', () => {
-    cursor.initialLineNumber = 1;
-    assert.isTrue(!!cursor.diffRow);
-    assert.equal(cursor.getTargetDiffElement(), diffElement);
-  });
-
-  suite('createCommentInPlace', () => {
-    setup(() => {
-      diffElement.loggedIn = true;
-    });
-
-    test('adds new draft for selected line on the left', async () => {
-      cursor.moveToLineNumber(2, Side.LEFT);
-      const promise = mockPromise();
-      diffElement.addEventListener('create-comment', e => {
-        const {lineNum, range, side} = e.detail;
-        assert.equal(lineNum, 2);
-        assert.equal(range, undefined);
-        assert.equal(side, Side.LEFT);
-        promise.resolve();
-      });
-      cursor.createCommentInPlace();
-      await promise;
-    });
-
-    test('adds draft for selected line on the right', async () => {
-      cursor.moveToLineNumber(4, Side.RIGHT);
-      const promise = mockPromise();
-      diffElement.addEventListener('create-comment', e => {
-        const {lineNum, range, side} = e.detail;
-        assert.equal(lineNum, 4);
-        assert.equal(range, undefined);
-        assert.equal(side, Side.RIGHT);
-        promise.resolve();
-      });
-      cursor.createCommentInPlace();
-      await promise;
-    });
-
-    test('creates comment for range if selected', async () => {
-      const someRange = {
-        start_line: 2,
-        start_character: 3,
-        end_line: 6,
-        end_character: 1,
-      };
-      diffElement.highlights.selectedRange = {
-        side: Side.RIGHT,
-        range: someRange,
-      };
-      const promise = mockPromise();
-      diffElement.addEventListener('create-comment', e => {
-        const {lineNum, range, side} = e.detail;
-        assert.equal(lineNum, 6);
-        assert.equal(range, someRange);
-        assert.equal(side, Side.RIGHT);
-        promise.resolve();
-      });
-      cursor.createCommentInPlace();
-      await promise;
-    });
-
-    test('ignores call if nothing is selected', () => {
-      const createRangeCommentStub = sinon.stub(
-        diffElement,
-        'createRangeComment'
-      );
-      const addDraftAtLineStub = sinon.stub(diffElement, 'addDraftAtLine');
-      cursor.diffRow = undefined;
-      cursor.createCommentInPlace();
-      assert.isFalse(createRangeCommentStub.called);
-      assert.isFalse(addDraftAtLineStub.called);
-    });
-  });
-
-  test('getAddress', () => {
-    // It should initialize to the first chunk: line 5 of the revision.
-    assert.deepEqual(cursor.getAddress(), {leftSide: false, number: 5});
-
-    // Revision line 4 is up.
-    cursor.moveUp();
-    assert.deepEqual(cursor.getAddress(), {leftSide: false, number: 4});
-
-    // Base line 4 is left.
-    cursor.moveLeft();
-    assert.deepEqual(cursor.getAddress(), {leftSide: true, number: 4});
-
-    // Moving to the next chunk takes it back to the start.
-    cursor.moveToNextChunk();
-    assert.deepEqual(cursor.getAddress(), {leftSide: false, number: 5});
-
-    // The following chunk is a removal starting on line 10 of the base.
-    cursor.moveToNextChunk();
-    assert.deepEqual(cursor.getAddress(), {leftSide: true, number: 10});
-
-    // Should be null if there is no selection.
-    cursor.cursorManager.unsetCursor();
-    assert.isNotOk(cursor.getAddress());
-  });
-
-  test('_findRowByNumberAndFile', () => {
-    // Get the first ab row after the first chunk.
-    const rows = [...queryAll<HTMLTableRowElement>(diffElement, 'tr')];
-    const row = rows[9];
-    assert.ok(row);
-
-    // It should be line 8 on the right, but line 5 on the left.
-    assert.equal(cursor._findRowByNumberAndFile(8, Side.RIGHT), row);
-    assert.equal(cursor._findRowByNumberAndFile(5, Side.LEFT), row);
-  });
-
-  test('expand context updates stops', async () => {
-    const spy = sinon.spy(cursor, '_updateStops');
-    const controls = queryAndAssert(diffElement, 'gr-context-controls');
-    const showContext = queryAndAssert<HTMLElement>(controls, '.showContext');
-    showContext.click();
-    await waitForEventOnce(diffElement, 'render');
-    await waitUntil(() => spy.called);
-    assert.isTrue(spy.called);
-  });
-
-  test('updates stops when loading changes', () => {
-    const spy = sinon.spy(cursor, '_updateStops');
-    diffElement.dispatchEvent(new Event('loading-changed'));
-    assert.isTrue(spy.called);
-  });
-
-  suite('multi diff', () => {
-    let diffElements: GrDiff[];
-
-    setup(async () => {
-      diffElements = [
-        await fixture(html`<gr-diff></gr-diff>`),
-        await fixture(html`<gr-diff></gr-diff>`),
-        await fixture(html`<gr-diff></gr-diff>`),
-      ];
-      cursor = new GrDiffCursor();
-
-      // Register the diff with the cursor.
-      cursor.replaceDiffs(diffElements);
-
-      for (const el of diffElements) {
-        el.prefs = createDefaultDiffPrefs();
-      }
-    });
-
-    function getTargetDiffIndex() {
-      // Mocha has a bug where when `assert.equals` fails, it will try to
-      // JSON.stringify the operands, which fails when they are cyclic structures
-      // like GrDiffElement. The failure is difficult to attribute to a specific
-      // assertion because of the async nature assertion errors are handled and
-      // can cause the test simply timing out, causing a lot of debugging headache.
-      // Working with indices circumvents the problem.
-      const target = cursor.getTargetDiffElement();
-      assertIsDefined(target);
-      return diffElements.indexOf(target);
-    }
-
-    test('do not skip loading diffs', async () => {
-      diffElements[0].diff = createDiff();
-      diffElements[2].diff = createDiff();
-      await waitForEventOnce(diffElements[0], 'render');
-      await waitForEventOnce(diffElements[2], 'render');
-
-      const lastLine = diffElements[0].diff.meta_b?.lines;
-      assertIsDefined(lastLine);
-
-      // Goto second last line of the first diff
-      cursor.moveToLineNumber(lastLine - 1, Side.RIGHT);
-      assert.equal(
-        cursor.getTargetLineElement()!.textContent?.trim(),
-        `${lastLine - 1}`
-      );
-
-      // Can move down until we reach the loading file
-      cursor.moveDown();
-      assert.equal(getTargetDiffIndex(), 0);
-      assert.equal(
-        cursor.getTargetLineElement()!.textContent?.trim(),
-        lastLine.toString()
-      );
-
-      // Cannot move down while still loading the diff we would switch to
-      cursor.moveDown();
-      assert.equal(getTargetDiffIndex(), 0);
-      assert.equal(
-        cursor.getTargetLineElement()!.textContent?.trim(),
-        lastLine.toString()
-      );
-
-      // Diff 1 finishing to load
-      diffElements[1].diff = createDiff();
-      await waitForEventOnce(diffElements[1], 'render');
-
-      // Now we can go down
-      cursor.moveDown(); // LOST
-      cursor.moveDown(); // FILE
-      assert.equal(getTargetDiffIndex(), 1);
-      assert.equal(cursor.getTargetLineElement()!.textContent?.trim(), 'File');
-    });
-  });
-});
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff-highlight/gr-annotation.ts b/polygerrit-ui/app/embed/diff-old/gr-diff-highlight/gr-annotation.ts
deleted file mode 100644
index 5669bcf..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff-highlight/gr-annotation.ts
+++ /dev/null
@@ -1,285 +0,0 @@
-/**
- * @license
- * Copyright 2016 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import {getSanitizeDOMValue} from '@polymer/polymer/lib/utils/settings';
-
-// TODO(wyatta): refactor this to be <MARK> rather than <HL>.
-const ANNOTATION_TAG = 'HL';
-
-// Astral code point as per https://mathiasbynens.be/notes/javascript-unicode
-const REGEX_ASTRAL_SYMBOL = /[\uD800-\uDBFF][\uDC00-\uDFFF]/;
-
-export const GrAnnotation = {
-  /**
-   * The DOM API textContent.length calculation is broken when the text
-   * contains Unicode. See https://mathiasbynens.be/notes/javascript-unicode .
-   *
-   */
-  getLength(node: Node) {
-    if (node instanceof Comment) return 0;
-    return GrAnnotation.getStringLength(node.textContent || '');
-  },
-
-  /**
-   * Returns the number of Unicode code points in the given string
-   *
-   * This is not necessarily the same as the number of visible symbols.
-   * See https://mathiasbynens.be/notes/javascript-unicode for more details.
-   */
-  getStringLength(str: string) {
-    return [...str].length;
-  },
-
-  /**
-   * Annotates the [offset, offset+length) text segment in the parent with the
-   * element definition provided as arguments.
-   *
-   * @param parent the node whose contents will be annotated.
-   * If parent is Text then parent.parentNode must not be null
-   * @param offset the 0-based offset from which the annotation will
-   * start.
-   * @param length of the annotated text.
-   * @param elementSpec the spec to create the
-   * annotating element.
-   */
-  annotateWithElement(
-    parent: Node,
-    offset: number,
-    length: number,
-    elSpec: ElementSpec
-  ) {
-    const tagName = elSpec.tagName;
-    const attributes = elSpec.attributes || {};
-    let childNodes: Node[];
-
-    if (parent instanceof Element) {
-      childNodes = Array.from(parent.childNodes);
-    } else if (parent instanceof Text) {
-      childNodes = [parent];
-      parent = parent.parentNode!;
-    } else {
-      return;
-    }
-
-    const nestedNodes: Node[] = [];
-    for (let node of childNodes) {
-      const initialNodeLength = GrAnnotation.getLength(node);
-      // If the current node is completely before the offset.
-      if (offset > 0 && initialNodeLength <= offset) {
-        offset -= initialNodeLength;
-        continue;
-      }
-
-      if (offset > 0) {
-        node = GrAnnotation.splitNode(node, offset);
-        offset = 0;
-      }
-      if (GrAnnotation.getLength(node) > length) {
-        GrAnnotation.splitNode(node, length);
-      }
-      nestedNodes.push(node);
-
-      length -= GrAnnotation.getLength(node);
-      if (!length) break;
-    }
-
-    const wrapper = document.createElement(tagName);
-    const sanitizer = getSanitizeDOMValue();
-    for (let [name, value] of Object.entries(attributes)) {
-      if (!value) continue;
-      if (sanitizer) {
-        value = sanitizer(value, name, 'attribute', wrapper) as string;
-      }
-      wrapper.setAttribute(name, value);
-    }
-    for (const inner of nestedNodes) {
-      parent.replaceChild(wrapper, inner);
-      wrapper.appendChild(inner);
-    }
-  },
-
-  /**
-   * Surrounds the element's text at specified range in an ANNOTATION_TAG
-   * element. If the element has child elements, the range is split and
-   * applied as deeply as possible.
-   */
-  annotateElement(
-    parent: HTMLElement,
-    offset: number,
-    length: number,
-    cssClass: string
-  ) {
-    const nodes: Array<HTMLElement | Text> = [].slice.apply(parent.childNodes);
-    let nodeLength;
-    let subLength;
-
-    for (const node of nodes) {
-      nodeLength = GrAnnotation.getLength(node);
-
-      // If the current node is completely before the offset.
-      if (nodeLength <= offset) {
-        offset -= nodeLength;
-        continue;
-      }
-
-      // Sublength is the annotation length for the current node.
-      subLength = Math.min(length, nodeLength - offset);
-
-      if (node instanceof Text) {
-        GrAnnotation._annotateText(node, offset, subLength, cssClass);
-      } else if (node instanceof Element) {
-        GrAnnotation.annotateElement(node, offset, subLength, cssClass);
-      }
-
-      // If there is still more to annotate, then shift the indices, otherwise
-      // work is done, so break the loop.
-      if (subLength < length) {
-        length -= subLength;
-        offset = 0;
-      } else {
-        break;
-      }
-    }
-  },
-
-  /**
-   * Wraps node in annotation tag with cssClass, replacing the node in DOM.
-   */
-  wrapInHighlight(node: Element | Text, cssClass: string) {
-    let hl;
-    if (!(node instanceof Text) && node.tagName === ANNOTATION_TAG) {
-      hl = node;
-      hl.classList.add(cssClass);
-    } else {
-      hl = document.createElement(ANNOTATION_TAG);
-      hl.className = cssClass;
-      if (node.parentElement) node.parentElement.replaceChild(hl, node);
-      hl.appendChild(node);
-    }
-    return hl;
-  },
-
-  /**
-   * Splits Text Node and wraps it in hl with cssClass.
-   * Wraps trailing part after split, tailing one if firstPart is true.
-   */
-  splitAndWrapInHighlight(
-    node: Text,
-    offset: number,
-    cssClass: string,
-    firstPart?: boolean
-  ) {
-    if (
-      (GrAnnotation.getLength(node) === offset && firstPart) ||
-      (offset === 0 && !firstPart)
-    ) {
-      return GrAnnotation.wrapInHighlight(node, cssClass);
-    }
-    if (firstPart) {
-      GrAnnotation.splitNode(node, offset);
-      // Node points to first part of the Text, second one is sibling.
-    } else {
-      // if node is Text then splitNode will return a Text
-      node = GrAnnotation.splitNode(node, offset) as Text;
-    }
-    return GrAnnotation.wrapInHighlight(node, cssClass);
-  },
-
-  /**
-   * Splits Node at offset.
-   * If Node is Element, it's cloned and the node at offset is split too.
-   */
-  splitNode(element: Node, offset: number) {
-    if (element instanceof Text) {
-      return GrAnnotation.splitTextNode(element, offset);
-    }
-    const tail = element.cloneNode(false);
-
-    if (element.parentElement)
-      element.parentElement.insertBefore(tail, element.nextSibling);
-    // Skip nodes before offset.
-    let node = element.firstChild;
-    while (
-      node &&
-      (GrAnnotation.getLength(node) <= offset ||
-        GrAnnotation.getLength(node) === 0)
-    ) {
-      offset -= GrAnnotation.getLength(node);
-      node = node.nextSibling;
-    }
-    if (node && GrAnnotation.getLength(node) > offset) {
-      tail.appendChild(GrAnnotation.splitNode(node, offset));
-    }
-    while (node && node.nextSibling) {
-      tail.appendChild(node.nextSibling);
-    }
-    return tail;
-  },
-
-  /**
-   * Node.prototype.splitText Unicode-valid alternative.
-   *
-   * DOM Api for splitText() is broken for Unicode:
-   * https://mathiasbynens.be/notes/javascript-unicode
-   *
-   * @return Trailing Text Node.
-   */
-  splitTextNode(node: Text, offset: number) {
-    if (node.textContent?.match(REGEX_ASTRAL_SYMBOL)) {
-      const head = Array.from(node.textContent);
-      const tail = head.splice(offset);
-      const parent = node.parentNode;
-
-      // Split the content of the original node.
-      node.textContent = head.join('');
-
-      const tailNode = document.createTextNode(tail.join(''));
-      if (parent) {
-        parent.insertBefore(tailNode, node.nextSibling);
-      }
-      return tailNode;
-    } else {
-      return node.splitText(offset);
-    }
-  },
-
-  _annotateText(node: Text, offset: number, length: number, cssClass: string) {
-    const nodeLength = GrAnnotation.getLength(node);
-
-    // There are four cases:
-    //  1) Entire node is highlighted.
-    //  2) Highlight is at the start.
-    //  3) Highlight is at the end.
-    //  4) Highlight is in the middle.
-
-    if (offset === 0 && nodeLength === length) {
-      // Case 1.
-      GrAnnotation.wrapInHighlight(node, cssClass);
-    } else if (offset === 0) {
-      // Case 2.
-      GrAnnotation.splitAndWrapInHighlight(node, length, cssClass, true);
-    } else if (offset + length === nodeLength) {
-      // Case 3
-      GrAnnotation.splitAndWrapInHighlight(node, offset, cssClass, false);
-    } else {
-      // Case 4
-      GrAnnotation.splitAndWrapInHighlight(
-        GrAnnotation.splitTextNode(node, offset),
-        length,
-        cssClass,
-        true
-      );
-    }
-  },
-};
-
-/**
- * Data used to construct an element.
- *
- */
-export interface ElementSpec {
-  tagName: string;
-  attributes?: {[attributeName: string]: string | undefined};
-}
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff-highlight/gr-annotation_test.ts b/polygerrit-ui/app/embed/diff-old/gr-diff-highlight/gr-annotation_test.ts
deleted file mode 100644
index 4543c10..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff-highlight/gr-annotation_test.ts
+++ /dev/null
@@ -1,308 +0,0 @@
-/**
- * @license
- * Copyright 2016 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import '../../../test/common-test-setup';
-import {GrAnnotation} from './gr-annotation';
-import {
-  getSanitizeDOMValue,
-  setSanitizeDOMValue,
-} from '@polymer/polymer/lib/utils/settings';
-import {assert, fixture, html} from '@open-wc/testing';
-
-suite('annotation', () => {
-  let str: string;
-  let parent: HTMLDivElement;
-  let textNode: Text;
-
-  setup(async () => {
-    parent = await fixture(
-      html`
-        <div>Lorem ipsum dolor sit amet, suspendisse inceptos vehicula</div>
-      `
-    );
-    textNode = parent.childNodes[0] as Text;
-    str = textNode.textContent!;
-  });
-
-  test('_annotateText length:0 offset:0', () => {
-    GrAnnotation._annotateText(textNode, 0, 0, 'foobar');
-
-    assert.equal(parent.textContent, str);
-    assert.equal(
-      parent.innerHTML,
-      '<hl class="foobar"></hl>Lorem ipsum dolor sit amet, suspendisse inceptos vehicula'
-    );
-  });
-
-  test('_annotateText length:0 offset:1', () => {
-    GrAnnotation._annotateText(textNode, 1, 0, 'foobar');
-
-    assert.equal(parent.textContent, str);
-    assert.equal(
-      parent.innerHTML,
-      'L<hl class="foobar"></hl>orem ipsum dolor sit amet, suspendisse inceptos vehicula'
-    );
-  });
-
-  test('_annotateText length:0 offset:str.length', () => {
-    GrAnnotation._annotateText(textNode, str.length, 0, 'foobar');
-
-    assert.equal(parent.textContent, str);
-    assert.equal(
-      parent.innerHTML,
-      'Lorem ipsum dolor sit amet, suspendisse inceptos vehicula<hl class="foobar"></hl>'
-    );
-  });
-
-  test('_annotateText Case 1', () => {
-    GrAnnotation._annotateText(textNode, 0, str.length, 'foobar');
-
-    assert.equal(parent.textContent, str);
-    assert.equal(
-      parent.innerHTML,
-      '<hl class="foobar">Lorem ipsum dolor sit amet, suspendisse inceptos vehicula</hl>'
-    );
-  });
-
-  test('_annotateText Case 2', () => {
-    GrAnnotation._annotateText(textNode, 0, 12, 'foobar');
-
-    assert.equal(parent.textContent, str);
-    assert.equal(
-      parent.innerHTML,
-      '<hl class="foobar">Lorem ipsum </hl>dolor sit amet, suspendisse inceptos vehicula'
-    );
-  });
-
-  test('_annotateText Case 3', () => {
-    GrAnnotation._annotateText(textNode, 12, str.length - 12, 'foobar');
-
-    assert.equal(parent.textContent, str);
-    assert.equal(
-      parent.innerHTML,
-      'Lorem ipsum <hl class="foobar">dolor sit amet, suspendisse inceptos vehicula</hl>'
-    );
-  });
-
-  test('_annotateText Case 4', () => {
-    const index = str.indexOf('dolor');
-    const length = 'dolor '.length;
-
-    GrAnnotation._annotateText(textNode, index, length, 'foobar');
-
-    assert.equal(parent.textContent, str);
-    assert.equal(
-      parent.innerHTML,
-      'Lorem ipsum <hl class="foobar">dolor </hl>sit amet, suspendisse inceptos vehicula'
-    );
-  });
-
-  test('_annotateElement design doc example', () => {
-    const layers = ['amet, ', 'inceptos ', 'amet, ', 'et, suspendisse ince'];
-
-    // Apply the layers successively.
-    layers.forEach((layer, i) => {
-      GrAnnotation.annotateElement(
-        parent,
-        str.indexOf(layer),
-        layer.length,
-        `layer-${i + 1}`
-      );
-    });
-
-    assert.equal(parent.textContent, str);
-    assert.equal(
-      parent.innerHTML,
-      'Lorem ipsum dolor sit <hl class="layer-1"><hl class="layer-3">am<hl class="layer-4">et, </hl></hl></hl><hl class="layer-4">suspendisse </hl><hl class="layer-2"><hl class="layer-4">ince</hl>ptos </hl>vehicula'
-    );
-  });
-
-  test('splitTextNode', () => {
-    const helloString = 'hello';
-    const asciiString = 'ASCII';
-    const unicodeString = 'Unic💢de';
-
-    let node;
-    let tail;
-
-    // Non-unicode path:
-    node = document.createTextNode(helloString + asciiString);
-    tail = GrAnnotation.splitTextNode(node, helloString.length);
-    assert(node.textContent, helloString);
-    assert(tail.textContent, asciiString);
-
-    // Unicdoe path:
-    node = document.createTextNode(helloString + unicodeString);
-    tail = GrAnnotation.splitTextNode(node, helloString.length);
-    assert(node.textContent, helloString);
-    assert(tail.textContent, unicodeString);
-  });
-
-  suite('annotateWithElement', () => {
-    const fullText = '01234567890123456789';
-    let mockSanitize: sinon.SinonSpy;
-    let originalSanitizeDOMValue: (
-      value: unknown,
-      name: string,
-      type: 'property' | 'attribute',
-      node: Node | null | undefined
-    ) => unknown;
-
-    setup(() => {
-      setSanitizeDOMValue(p0 => p0);
-      originalSanitizeDOMValue = getSanitizeDOMValue()!;
-      assert.isDefined(originalSanitizeDOMValue);
-      mockSanitize = sinon.spy(originalSanitizeDOMValue);
-      setSanitizeDOMValue(mockSanitize);
-    });
-
-    teardown(() => {
-      setSanitizeDOMValue(originalSanitizeDOMValue);
-    });
-
-    test('annotates when fully contained', () => {
-      const length = 10;
-      const container = document.createElement('div');
-      container.textContent = fullText;
-      GrAnnotation.annotateWithElement(container, 1, length, {
-        tagName: 'test-wrapper',
-      });
-
-      assert.equal(
-        container.innerHTML,
-        '0<test-wrapper>1234567890</test-wrapper>123456789'
-      );
-    });
-
-    test('annotates when spanning multiple nodes', () => {
-      const length = 10;
-      const container = document.createElement('div');
-      container.textContent = fullText;
-      GrAnnotation.annotateElement(container, 5, length, 'testclass');
-      GrAnnotation.annotateWithElement(container, 1, length, {
-        tagName: 'test-wrapper',
-      });
-
-      assert.equal(
-        container.innerHTML,
-        '0' +
-          '<test-wrapper>' +
-          '1234' +
-          '<hl class="testclass">567890</hl>' +
-          '</test-wrapper>' +
-          '<hl class="testclass">1234</hl>' +
-          '56789'
-      );
-    });
-
-    test('annotates text node', () => {
-      const length = 10;
-      const container = document.createElement('div');
-      container.textContent = fullText;
-      GrAnnotation.annotateWithElement(container.childNodes[0], 1, length, {
-        tagName: 'test-wrapper',
-      });
-
-      assert.equal(
-        container.innerHTML,
-        '0<test-wrapper>1234567890</test-wrapper>123456789'
-      );
-    });
-
-    test('handles zero-length nodes', () => {
-      const container = document.createElement('div');
-      container.appendChild(document.createTextNode('0123456789'));
-      container.appendChild(document.createElement('span'));
-      container.appendChild(document.createTextNode('0123456789'));
-      GrAnnotation.annotateWithElement(container, 1, 10, {
-        tagName: 'test-wrapper',
-      });
-
-      assert.equal(
-        container.innerHTML,
-        '0<test-wrapper>123456789<span></span>0</test-wrapper>123456789'
-      );
-    });
-
-    test('handles comment nodes', () => {
-      const container = document.createElement('div');
-      container.appendChild(document.createComment('comment1'));
-      container.appendChild(document.createTextNode('0123456789'));
-      container.appendChild(document.createComment('comment2'));
-      container.appendChild(document.createElement('span'));
-      container.appendChild(document.createTextNode('0123456789'));
-      GrAnnotation.annotateWithElement(container, 1, 10, {
-        tagName: 'test-wrapper',
-      });
-
-      assert.equal(
-        container.innerHTML,
-        '<!--comment1-->' +
-          '0<test-wrapper>123456789' +
-          '<!--comment2-->' +
-          '<span></span>0</test-wrapper>123456789'
-      );
-    });
-
-    test('sets sanitized attributes', () => {
-      const container = document.createElement('div');
-      container.textContent = fullText;
-      const attributes = {
-        href: 'foo',
-        'data-foo': 'bar',
-        class: 'hello world',
-      };
-      GrAnnotation.annotateWithElement(container, 1, length, {
-        tagName: 'test-wrapper',
-        attributes,
-      });
-      assert(
-        mockSanitize.calledWith(
-          'foo',
-          'href',
-          'attribute',
-          sinon.match.instanceOf(Element)
-        )
-      );
-      assert(
-        mockSanitize.calledWith(
-          'bar',
-          'data-foo',
-          'attribute',
-          sinon.match.instanceOf(Element)
-        )
-      );
-      assert(
-        mockSanitize.calledWith(
-          'hello world',
-          'class',
-          'attribute',
-          sinon.match.instanceOf(Element)
-        )
-      );
-      const el = container.querySelector('test-wrapper')!;
-      assert.equal(el.getAttribute('href'), 'foo');
-      assert.equal(el.getAttribute('data-foo'), 'bar');
-      assert.equal(el.getAttribute('class'), 'hello world');
-    });
-  });
-
-  suite('getStringLength', () => {
-    test('ASCII characters are counted correctly', () => {
-      assert.equal(GrAnnotation.getStringLength('ASCII'), 5);
-    });
-
-    test('Unicode surrogate pairs count as one symbol', () => {
-      assert.equal(GrAnnotation.getStringLength('Unic💢de'), 7);
-      assert.equal(GrAnnotation.getStringLength('💢💢'), 2);
-    });
-
-    test('Grapheme clusters count as multiple symbols', () => {
-      assert.equal(GrAnnotation.getStringLength('man\u0303ana'), 7); // mañana
-      assert.equal(GrAnnotation.getStringLength('q\u0307\u0323'), 3); // q̣̇
-    });
-  });
-});
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff-highlight/gr-diff-highlight.ts b/polygerrit-ui/app/embed/diff-old/gr-diff-highlight/gr-diff-highlight.ts
deleted file mode 100644
index 2c0663d..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff-highlight/gr-diff-highlight.ts
+++ /dev/null
@@ -1,525 +0,0 @@
-/**
- * @license
- * Copyright 2016 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import '../../../styles/shared-styles';
-import '../../diff/gr-selection-action-box/gr-selection-action-box';
-import {GrAnnotation} from './gr-annotation';
-import {normalize} from './gr-range-normalizer';
-import {strToClassName} from '../../../utils/dom-util';
-import {Side} from '../../../constants/constants';
-import {CommentRange} from '../../../types/common';
-import {GrSelectionActionBox} from '../../diff/gr-selection-action-box/gr-selection-action-box';
-import {
-  getLineElByChild,
-  getLineNumberByChild,
-  getSideByLineEl,
-  GrDiffThreadElement,
-} from '../../diff/gr-diff/gr-diff-utils';
-import {debounce, DelayedTask} from '../../../utils/async-util';
-import {assertIsDefined, queryAndAssert} from '../../../utils/common-util';
-import {fire} from '../../../utils/event-util';
-
-interface SidedRange {
-  side: Side;
-  range: CommentRange;
-}
-
-interface NormalizedPosition {
-  node: Node | null;
-  side: Side;
-  line: number;
-  column: number;
-}
-
-interface NormalizedRange {
-  start: NormalizedPosition | null;
-  end: NormalizedPosition | null;
-}
-
-/**
- * The methods that we actually want to call on the builder. We don't want a
- * fully blown dependency on GrDiffBuilderElement.
- */
-export interface DiffBuilderInterface {
-  getContentTdByLineEl(lineEl?: Element): Element | undefined;
-}
-
-/**
- * Handles showing, positioning and interacting with <gr-selection-action-box>.
- *
- * Toggles a css class for highlighting comment ranges when the mouse leaves or
- * enters a comment thread element.
- */
-export class GrDiffHighlight {
-  selectedRange?: SidedRange;
-
-  private diffBuilder?: DiffBuilderInterface;
-
-  private diffTable?: HTMLElement;
-
-  private selectionChangeTask?: DelayedTask;
-
-  init(diffTable: HTMLElement, diffBuilder: DiffBuilderInterface) {
-    this.cleanup();
-
-    this.diffTable = diffTable;
-    this.diffBuilder = diffBuilder;
-
-    diffTable.addEventListener(
-      'comment-thread-mouseleave',
-      this.handleCommentThreadMouseleave
-    );
-    diffTable.addEventListener(
-      'comment-thread-mouseenter',
-      this.handleCommentThreadMouseenter
-    );
-    diffTable.addEventListener(
-      'create-comment-requested',
-      this.handleRangeCommentRequest
-    );
-  }
-
-  cleanup() {
-    this.selectionChangeTask?.cancel();
-    if (this.diffTable) {
-      this.diffTable.removeEventListener(
-        'comment-thread-mouseleave',
-        this.handleCommentThreadMouseleave
-      );
-      this.diffTable.removeEventListener(
-        'comment-thread-mouseenter',
-        this.handleCommentThreadMouseenter
-      );
-      this.diffTable.removeEventListener(
-        'create-comment-requested',
-        this.handleRangeCommentRequest
-      );
-    }
-  }
-
-  /**
-   * Determines side/line/range for a DOM selection and shows a tooltip.
-   *
-   * With native shadow DOM, gr-diff-highlight cannot access a selection that
-   * references the DOM elements making up the diff because they are in the
-   * shadow DOM the gr-diff element. For this reason, we listen to the
-   * selectionchange event and retrieve the selection in gr-diff, and then
-   * call this method to process the Selection.
-   *
-   * @param selection A DOM Selection living in the shadow DOM of
-   * the diff element.
-   * @param isMouseUp If true, this is called due to a mouseup
-   * event, in which case we might want to immediately create a comment,
-   * because isMouseUp === true combined with an existing selection must
-   * mean that this is the end of a double-click.
-   */
-  handleSelectionChange(
-    selection: Selection | Range | null,
-    isMouseUp: boolean
-  ) {
-    if (selection === null) return;
-    // Debounce is not just nice for waiting until the selection has settled,
-    // it is also vital for being able to click on the action box before it is
-    // removed.
-    // If you wait longer than 50 ms, then you don't properly catch a very
-    // quick 'c' press after the selection change. If you wait less than 10
-    // ms, then you will have about 50 handleSelection() calls when doing a
-    // simple drag for select.
-    this.selectionChangeTask = debounce(
-      this.selectionChangeTask,
-      () => this.handleSelection(selection, isMouseUp),
-      10
-    );
-  }
-
-  private getThreadEl(e: Event): GrDiffThreadElement | null {
-    for (const pathEl of e.composedPath()) {
-      if (
-        pathEl instanceof HTMLElement &&
-        pathEl.classList.contains('comment-thread')
-      ) {
-        return pathEl as GrDiffThreadElement;
-      }
-    }
-    return null;
-  }
-
-  private toggleRangeElHighlight(
-    threadEl: GrDiffThreadElement | null,
-    highlightRange = false
-  ) {
-    const rootId = threadEl?.rootId;
-    if (!rootId) return;
-    if (!this.diffTable) return;
-    if (highlightRange) {
-      const selector = `.range.${strToClassName(rootId)}`;
-      const rangeNodes = this.diffTable.querySelectorAll(selector);
-      rangeNodes.forEach(rangeNode => {
-        rangeNode.classList.add('rangeHoverHighlight');
-      });
-      const hintNode = this.diffTable.querySelector(
-        `gr-ranged-comment-hint[threadElRootId="${rootId}"]`
-      );
-      hintNode?.shadowRoot
-        ?.querySelectorAll('.rangeHighlight')
-        .forEach(highlightNode =>
-          highlightNode.classList.add('rangeHoverHighlight')
-        );
-    } else {
-      const selector = `.rangeHoverHighlight.${strToClassName(rootId)}`;
-      const rangeNodes = this.diffTable.querySelectorAll(selector);
-      rangeNodes.forEach(rangeNode => {
-        rangeNode.classList.remove('rangeHoverHighlight');
-      });
-      const hintNode = this.diffTable.querySelector(
-        `gr-ranged-comment-hint[threadElRootId="${rootId}"]`
-      );
-      hintNode?.shadowRoot
-        ?.querySelectorAll('.rangeHoverHighlight')
-        .forEach(highlightNode =>
-          highlightNode.classList.remove('rangeHoverHighlight')
-        );
-    }
-  }
-
-  private handleCommentThreadMouseenter = (e: Event) => {
-    const threadEl = this.getThreadEl(e);
-    this.toggleRangeElHighlight(threadEl, /* highlightRange= */ true);
-  };
-
-  private handleCommentThreadMouseleave = (e: Event) => {
-    const threadEl = this.getThreadEl(e);
-    this.toggleRangeElHighlight(threadEl, /* highlightRange= */ false);
-  };
-
-  /**
-   * Get current normalized selection.
-   * Merges multiple ranges, accounts for triple click, accounts for
-   * syntax highligh, convert native DOM Range objects to Gerrit concepts
-   * (line, side, etc).
-   */
-  private getNormalizedRange(selection: Selection | Range) {
-    /* On Safari the ShadowRoot.getSelection() isn't there and the only thing
-       we can get is a single Range */
-    if (selection instanceof Range) {
-      return this.normalizeRange(selection);
-    }
-    const rangeCount = selection.rangeCount;
-    if (rangeCount === 0) {
-      return null;
-    } else if (rangeCount === 1) {
-      return this.normalizeRange(selection.getRangeAt(0));
-    } else {
-      const startRange = this.normalizeRange(selection.getRangeAt(0));
-      const endRange = this.normalizeRange(
-        selection.getRangeAt(rangeCount - 1)
-      );
-      return {
-        start: startRange.start,
-        end: endRange.end,
-      };
-    }
-  }
-
-  /**
-   * Normalize a specific DOM Range.
-   *
-   * @return fixed normalized range
-   */
-  private normalizeRange(domRange: Range): NormalizedRange {
-    const range = normalize(domRange);
-    return this.fixTripleClickSelection(
-      {
-        start: this.normalizeSelectionSide(
-          range.startContainer,
-          range.startOffset
-        ),
-        end: this.normalizeSelectionSide(range.endContainer, range.endOffset),
-      },
-      domRange
-    );
-  }
-
-  /**
-   * Adjust triple click selection for the whole line.
-   * A triple click always results in:
-   * - start.column == end.column == 0
-   * - end.line == start.line + 1
-   *
-   * @param range Normalized range, ie column/line numbers
-   * @param domRange DOM Range object
-   * @return fixed normalized range
-   */
-  private fixTripleClickSelection(range: NormalizedRange, domRange: Range) {
-    if (!range.start) {
-      // Selection outside of current diff.
-      return range;
-    }
-    const start = range.start;
-    const end = range.end;
-    // Happens when triple click in side-by-side mode with other side empty.
-    const endsAtOtherEmptySide =
-      !end &&
-      domRange.endOffset === 0 &&
-      domRange.endContainer instanceof HTMLElement &&
-      domRange.endContainer.nodeName === 'TD' &&
-      (domRange.endContainer.classList.contains('left') ||
-        domRange.endContainer.classList.contains('right'));
-    const endsAtBeginningOfNextLine =
-      end &&
-      start.column === 0 &&
-      end.column === 0 &&
-      end.line === start.line + 1;
-    const content = domRange.cloneContents().querySelector('.contentText');
-    const lineLength = (content && this.getLength(content)) || 0;
-    if (lineLength && (endsAtBeginningOfNextLine || endsAtOtherEmptySide)) {
-      // Move the selection to the end of the previous line.
-      range.end = {
-        node: start.node,
-        column: lineLength,
-        side: start.side,
-        line: start.line,
-      };
-    }
-    return range;
-  }
-
-  /**
-   * Convert DOM Range selection to concrete numbers (line, column, side).
-   * Moves range end if it's not inside td.content.
-   * Returns null if selection end is not valid (outside of diff).
-   *
-   * @param node td.content child
-   * @param offset offset within node
-   */
-  private normalizeSelectionSide(
-    node: Node | null,
-    offset: number
-  ): NormalizedPosition | null {
-    let column;
-    if (!this.diffTable) return null;
-    if (!this.diffBuilder) return null;
-    if (!node || !this.diffTable.contains(node)) return null;
-    const lineEl = getLineElByChild(node);
-    if (!lineEl) return null;
-    const side = getSideByLineEl(lineEl);
-    if (!side) return null;
-    const line = getLineNumberByChild(lineEl);
-    if (typeof line !== 'number') return null;
-    const contentTd = this.diffBuilder.getContentTdByLineEl(lineEl);
-    if (!contentTd) return null;
-    const contentText = contentTd.querySelector('.contentText');
-    if (!contentTd.contains(node)) {
-      node = contentText;
-      column = 0;
-    } else {
-      const thread = contentTd.querySelector('.comment-thread');
-      if (thread?.contains(node)) {
-        column = this.getLength(contentText);
-        node = contentText;
-      } else {
-        column = this.convertOffsetToColumn(node, offset);
-      }
-    }
-
-    return {
-      node,
-      side,
-      line,
-      column,
-    };
-  }
-
-  /**
-   * The only line in which add a comment tooltip is cut off is the first
-   * line. Even if there is a collapsed section, The first visible line is
-   * in the position where the second line would have been, if not for the
-   * collapsed section, so don't need to worry about this case for
-   * positioning the tooltip.
-   */
-  // visible for testing
-  positionActionBox(
-    actionBox: GrSelectionActionBox,
-    startLine: number,
-    range: Text | Element | Range
-  ) {
-    if (startLine > 1) {
-      actionBox.positionBelow = false;
-      actionBox.placeAbove(range);
-      return;
-    }
-    actionBox.positionBelow = true;
-    actionBox.placeBelow(range);
-  }
-
-  private isRangeValid(range: NormalizedRange | null) {
-    if (!range || !range.start || !range.start.node || !range.end) {
-      return false;
-    }
-    const start = range.start;
-    const end = range.end;
-    return !(
-      start.side !== end.side ||
-      end.line < start.line ||
-      (start.line === end.line && start.column === end.column)
-    );
-  }
-
-  // visible for testing
-  handleSelection(selection: Selection | Range, isMouseUp: boolean) {
-    /* On Safari, the selection events may return a null range that should
-       be ignored */
-    if (!selection) return;
-    if (!this.diffTable) return;
-
-    const normalizedRange = this.getNormalizedRange(selection);
-    if (!this.isRangeValid(normalizedRange)) {
-      this.removeActionBox();
-      return;
-    }
-    /* On Safari the ShadowRoot.getSelection() isn't there and the only thing
-       we can get is a single Range */
-    const domRange =
-      selection instanceof Range ? selection : selection.getRangeAt(0);
-    const start = normalizedRange!.start!;
-    const end = normalizedRange!.end!;
-
-    // TODO (viktard): Drop empty first and last lines from selection.
-
-    // If the selection is from the end of one line to the start of the next
-    // line, then this must have been a double-click, or you have started
-    // dragging. Showing the action box is bad in the former case and not very
-    // useful in the latter, so never do that.
-    // If this was a mouse-up event, we create a comment immediately if
-    // the selection is from the end of a line to the start of the next line.
-    // In a perfect world we would only do this for double-click, but it is
-    // extremely rare that a user would drag from the end of one line to the
-    // start of the next and release the mouse, so we don't bother.
-    // TODO(brohlfs): This does not work, if the double-click is before a new
-    // diff chunk (start will be equal to end), and neither before an "expand
-    // the diff context" block (end line will match the first line of the new
-    // section and thus be greater than start line + 1).
-    if (start.line === end.line - 1 && end.column === 0) {
-      // Rather than trying to find the line contents (for comparing
-      // start.column with the content length), we just check if the selection
-      // is empty to see that it's at the end of a line.
-      const content = domRange.cloneContents().querySelector('.contentText');
-      if (isMouseUp && this.getLength(content) === 0) {
-        this.fireCreateRangeComment(start.side, {
-          start_line: start.line,
-          start_character: 0,
-          end_line: start.line,
-          end_character: start.column,
-        });
-      }
-      return;
-    }
-
-    let actionBox = this.diffTable.querySelector('gr-selection-action-box');
-    if (!actionBox) {
-      actionBox = document.createElement('gr-selection-action-box');
-      this.diffTable.appendChild(actionBox);
-    }
-    this.selectedRange = {
-      range: {
-        start_line: start.line,
-        start_character: start.column,
-        end_line: end.line,
-        end_character: end.column,
-      },
-      side: start.side,
-    };
-    if (start.line === end.line) {
-      this.positionActionBox(actionBox, start.line, domRange);
-    } else if (start.node instanceof Text) {
-      if (start.column) {
-        this.positionActionBox(
-          actionBox,
-          start.line,
-          start.node.splitText(start.column)
-        );
-      }
-      start.node.parentElement!.normalize(); // Undo splitText from above.
-    } else if (
-      start.node instanceof HTMLElement &&
-      start.node.classList.contains('content') &&
-      (start.node.firstChild instanceof Element ||
-        start.node.firstChild instanceof Text)
-    ) {
-      this.positionActionBox(actionBox, start.line, start.node.firstChild);
-    } else if (start.node instanceof Element || start.node instanceof Text) {
-      this.positionActionBox(actionBox, start.line, start.node);
-    } else {
-      console.warn('Failed to position comment action box.');
-      this.removeActionBox();
-    }
-  }
-
-  private fireCreateRangeComment(side: Side, range: CommentRange) {
-    if (this.diffTable) {
-      fire(this.diffTable, 'create-range-comment', {side, range});
-    }
-    this.removeActionBox();
-  }
-
-  private handleRangeCommentRequest = (e: Event) => {
-    e.stopPropagation();
-    assertIsDefined(this.selectedRange, 'selectedRange');
-    const {side, range} = this.selectedRange;
-    this.fireCreateRangeComment(side, range);
-  };
-
-  // visible for testing
-  removeActionBox() {
-    this.selectedRange = undefined;
-    const actionBox = this.diffTable?.querySelector('gr-selection-action-box');
-    if (actionBox) actionBox.remove();
-  }
-
-  private convertOffsetToColumn(el: Node, offset: number) {
-    if (el instanceof Element && el.classList.contains('content')) {
-      return offset;
-    }
-    while (
-      el.previousSibling ||
-      !el.parentElement?.classList.contains('content')
-    ) {
-      if (el.previousSibling) {
-        el = el.previousSibling;
-        offset += this.getLength(el);
-      } else {
-        el = el.parentElement!;
-      }
-    }
-    return offset;
-  }
-
-  /**
-   * Get length of a node. If the node is a content node, then only give the
-   * length of its .contentText child.
-   *
-   * @param node this is sometimes passed as null.
-   */
-  // visible for testing
-  getLength(node: Node | null): number {
-    if (node === null) return 0;
-    if (node instanceof Element && node.classList.contains('content')) {
-      return this.getLength(queryAndAssert(node, '.contentText'));
-    } else {
-      return GrAnnotation.getLength(node);
-    }
-  }
-}
-
-export interface CreateRangeCommentEventDetail {
-  side: Side;
-  range: CommentRange;
-}
-
-declare global {
-  interface HTMLElementEventMap {
-    'create-range-comment': CustomEvent<CreateRangeCommentEventDetail>;
-  }
-}
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff-highlight/gr-diff-highlight_test.ts b/polygerrit-ui/app/embed/diff-old/gr-diff-highlight/gr-diff-highlight_test.ts
deleted file mode 100644
index e491e63..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff-highlight/gr-diff-highlight_test.ts
+++ /dev/null
@@ -1,717 +0,0 @@
-/**
- * @license
- * Copyright 2016 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import '../../../test/common-test-setup';
-import './gr-diff-highlight';
-import {getTextOffset} from './gr-range-normalizer';
-import {fixture, fixtureCleanup, html, assert} from '@open-wc/testing';
-import {
-  GrDiffHighlight,
-  DiffBuilderInterface,
-  CreateRangeCommentEventDetail,
-} from './gr-diff-highlight';
-import {Side} from '../../../api/diff';
-import {SinonStubbedMember} from 'sinon';
-import {queryAndAssert} from '../../../utils/common-util';
-import {GrDiffThreadElement} from '../../diff/gr-diff/gr-diff-utils';
-import {
-  stubElement,
-  waitQueryAndAssert,
-  waitUntil,
-} from '../../../test/test-utils';
-import {GrSelectionActionBox} from '../../diff/gr-selection-action-box/gr-selection-action-box';
-
-// Splitting long lines in html into shorter rows breaks tests:
-// zero-length text nodes and new lines are not expected in some places
-/* eslint-disable max-len, lit/prefer-static-styles */
-/* prettier-ignore */
-const diffTable = html`
-  <table id="diffTable">
-    <tbody class="section both">
-      <tr class="diff-row side-by-side" left-type="both" right-type="both">
-        <td class="left lineNum" data-value="1"></td>
-        <td class="content both"><div class="contentText">[1] Nam cum ad me in Cumanum salutandi causa uterque venisset,</div></td>
-        <td class="right lineNum" data-value="1"></td>
-        <td class="content both"><div class="contentText">[1] Nam cum ad me in Cumanum salutandi causa uterque</div></td>
-      </tr>
-    </tbody>
-
-    <tbody class="section delta">
-      <tr class="diff-row side-by-side" left-type="remove" right-type="add">
-        <td class="left lineNum" data-value="2"></td>
-        <!-- Next tag is formatted to eliminate zero-length text nodes. -->
-        <td class="content remove"><div class="contentText">na💢ti <hl class="foo range generated_id314">te, inquit</hl>, sumus<hl class="bar">aliquando</hl> otiosum, <hl>certe</hl> a<hl><span class="tab-indicator" style="tab-size:8;"> </span></hl>udiam, <hl>quid</hl> sit,<span class="tab-indicator" style="tab-size:8;"> </span>quod<hl>Epicurum</hl></div></td>
-        <td class="right lineNum" data-value="2"></td>
-        <!-- Next tag is formatted to eliminate zero-length text nodes. -->
-        <td class="content add"><div class="contentText">nacti , <hl>,</hl> sumus<hl><span class="tab-indicator" style="tab-size:8;"> </span></hl>otiosum,<span class="tab-indicator" style="tab-size:8;"> </span> audiam,sit, quod</div></td>
-      </tr>
-    </tbody>
-
-    <tbody class="section both">
-      <tr class="diff-row side-by-side" left-type="both" right-type="both">
-        <td class="left lineNum" data-value="138"></td>
-        <td class="content both"><div class="contentText">[14] Nam cum ad me in Cumanum salutandi causa uterque venisset,</div></td>
-        <td class="right lineNum" data-value="119"></td>
-        <td class="content both"><div class="contentText">[14] Nam cum ad me in Cumanum salutandi causa uterque venisset,</div></td>
-      </tr>
-    </tbody>
-
-    <tbody class="section delta">
-      <tr class="diff-row side-by-side" left-type="remove" right-type="add">
-        <td class="left lineNum" data-value="140"></td>
-        <!-- Next tag is formatted to eliminate zero-length text nodes. -->
-        <td class="content remove"><div class="contentText"><!-- a comment node -->na💢ti <hl class="foo">te, inquit</hl>, sumus <hl class="bar">aliquando</hl> otiosum, <hl>certe</hl> a <hl><span class="tab-indicator" style="tab-size:8;">\u0009</span></hl>udiam, <hl>quid</hl> sit, <span class="tab-indicator" style="tab-size:8;">\u0009</span>quod <hl>Epicurum</hl></div><div class="comment-thread">
-          [Yet another random diff thread content here]
-        </div></td>
-        <td class="right lineNum" data-value="120"></td>
-        <!-- Next tag is formatted to eliminate zero-length text nodes. -->
-        <td class="content add"><div class="contentText">nacti , <hl>,</hl> sumus <hl><span class="tab-indicator" style="tab-size:8;">\u0009</span></hl> otiosum,  <span class="tab-indicator" style="tab-size:8;">\u0009</span> audiam,  sit, quod</div></td>
-      </tr>
-    </tbody>
-
-    <tbody class="section both">
-      <tr class="diff-row side-by-side" left-type="both" right-type="both">
-        <td class="left lineNum" data-value="141"></td>
-        <td class="content both"><div class="contentText">nam et<hl><span class="tab-indicator" style="tab-size:8;"> </span></hl>complectitur<span class="tab-indicator" style="tab-size:8;"></span>verbis, quod vult, et dicit plane, quod intellegam;</div></td>
-        <td class="right lineNum" data-value="130"></td>
-        <td class="content both"><div class="contentText">nam et complectitur verbis, quod vult, et dicit plane, quodintellegam;</div></td>
-      </tr>
-    </tbody>
-
-    <tbody class="section contextControl">
-      <tr
-        class="diff-row side-by-side"
-        left-type="contextControl"
-        right-type="contextControl"
-      >
-        <td class="left contextLineNum"></td>
-        <td>
-          <gr-button>+10↑</gr-button>
-          -
-          <gr-button>Show 21 common lines</gr-button>
-          -
-          <gr-button>+10↓</gr-button>
-        </td>
-        <td class="right contextLineNum"></td>
-        <td>
-          <gr-button>+10↑</gr-button>
-          -
-          <gr-button>Show 21 common lines</gr-button>
-          -
-          <gr-button>+10↓</gr-button>
-        </td>
-      </tr>
-    </tbody>
-
-    <tbody class="section delta total">
-      <tr class="diff-row side-by-side" left-type="blank" right-type="add">
-        <td class="left"></td>
-        <td class="blank"></td>
-        <td class="right lineNum" data-value="146"></td>
-        <td class="content add"><div class="contentText">[17] Quid igitur est? inquit; audire enim cupio, quid non probes. Principio, inquam,</div></td>
-      </tr>
-    </tbody>
-
-    <tbody class="section both">
-      <tr class="diff-row side-by-side" left-type="both" right-type="both">
-        <td class="left lineNum" data-value="165"></td>
-        <td class="content both"><div class="contentText"></div></td>
-        <td class="right lineNum" data-value="147"></td>
-        <td class="content both"><div class="contentText">in physicis, <hl><span class="tab-indicator" style="tab-size:8;"> </span></hl>quibus maxime gloriatur, primum totus est alienus. Democritea dicit</div></td>
-      </tr>
-    </tbody>
-  </table>
-`;
-/* eslint-enable max-len */
-
-suite('gr-diff-highlight', () => {
-  suite('comment events', () => {
-    let threadEl: GrDiffThreadElement;
-    let hlRange: HTMLElement;
-    let element: GrDiffHighlight;
-    let diff: HTMLElement;
-    let builder: {
-      getContentTdByLineEl: SinonStubbedMember<
-        DiffBuilderInterface['getContentTdByLineEl']
-      >;
-    };
-
-    setup(async () => {
-      diff = await fixture<HTMLTableElement>(diffTable);
-      builder = {
-        getContentTdByLineEl: sinon.stub(),
-      };
-      element = new GrDiffHighlight();
-      element.init(diff, builder);
-      hlRange = queryAndAssert(diff, 'hl.range.generated_id314');
-
-      threadEl = document.createElement(
-        'div'
-      ) as unknown as GrDiffThreadElement;
-      threadEl.className = 'comment-thread';
-      threadEl.rootId = 'id314';
-      diff.appendChild(threadEl);
-    });
-
-    teardown(() => {
-      element.cleanup();
-      threadEl.remove();
-    });
-
-    test('comment-thread-mouseenter toggles rangeHoverHighlight class', async () => {
-      assert.isFalse(hlRange.classList.contains('rangeHoverHighlight'));
-      threadEl.dispatchEvent(
-        new CustomEvent('comment-thread-mouseenter', {
-          bubbles: true,
-          composed: true,
-        })
-      );
-      await waitUntil(() => hlRange.classList.contains('rangeHoverHighlight'));
-      assert.isTrue(hlRange.classList.contains('rangeHoverHighlight'));
-    });
-
-    test('comment-thread-mouseleave toggles rangeHoverHighlight class', async () => {
-      hlRange.classList.add('rangeHoverHighlight');
-      threadEl.dispatchEvent(
-        new CustomEvent('comment-thread-mouseleave', {
-          bubbles: true,
-          composed: true,
-        })
-      );
-      await waitUntil(() => !hlRange.classList.contains('rangeHoverHighlight'));
-      assert.isFalse(hlRange.classList.contains('rangeHoverHighlight'));
-    });
-
-    test(`create-range-comment for range when create-comment-requested
-          is fired`, () => {
-      const removeActionBoxStub = sinon.stub(element, 'removeActionBox');
-      element.selectedRange = {
-        side: Side.LEFT,
-        range: {
-          start_line: 7,
-          start_character: 11,
-          end_line: 24,
-          end_character: 42,
-        },
-      };
-      const requestEvent = new CustomEvent('create-comment-requested');
-      let createRangeEvent: CustomEvent<CreateRangeCommentEventDetail>;
-      diff.addEventListener('create-range-comment', e => {
-        createRangeEvent = e;
-      });
-      diff.dispatchEvent(requestEvent);
-      if (!createRangeEvent!) assert.fail('event not set');
-      assert.deepEqual(element.selectedRange, createRangeEvent.detail);
-      assert.isTrue(removeActionBoxStub.called);
-    });
-  });
-
-  suite('selection', () => {
-    let element: GrDiffHighlight;
-    let diff: HTMLElement;
-    let builder: {
-      getContentTdByLineEl: SinonStubbedMember<
-        DiffBuilderInterface['getContentTdByLineEl']
-      >;
-    };
-    let contentStubs;
-
-    setup(async () => {
-      diff = await fixture<HTMLTableElement>(diffTable);
-      builder = {
-        getContentTdByLineEl: sinon.stub(),
-      };
-      element = new GrDiffHighlight();
-      element.init(diff, builder);
-      contentStubs = [];
-      stubElement('gr-selection-action-box', 'placeAbove');
-      stubElement('gr-selection-action-box', 'placeBelow');
-    });
-
-    teardown(() => {
-      fixtureCleanup();
-      element.cleanup();
-      contentStubs = null;
-      document.getSelection()!.removeAllRanges();
-    });
-
-    const stubContent = (line: number, side: Side) => {
-      const contentTd = diff.querySelector(
-        `.${side}.lineNum[data-value="${line}"] ~ .content`
-      );
-      if (!contentTd) assert.fail('content td not found');
-      const contentText = contentTd.querySelector('.contentText');
-      const lineEl =
-        diff.querySelector(`.${side}.lineNum[data-value="${line}"]`) ??
-        undefined;
-      contentStubs.push({
-        lineEl,
-        contentTd,
-        contentText,
-      });
-      builder.getContentTdByLineEl.withArgs(lineEl).returns(contentTd);
-      return contentText;
-    };
-
-    const emulateSelection = (
-      startNode: Node,
-      startOffset: number,
-      endNode: Node,
-      endOffset: number
-    ) => {
-      const selection = document.getSelection();
-      if (!selection) assert.fail('no selection');
-      selection.removeAllRanges();
-      const range = document.createRange();
-      range.setStart(startNode, startOffset);
-      range.setEnd(endNode, endOffset);
-      selection.addRange(range);
-      element.handleSelection(selection, false);
-    };
-
-    test('single first line', () => {
-      const content = stubContent(1, Side.RIGHT);
-      sinon.spy(element, 'positionActionBox');
-      if (!content?.firstChild) assert.fail('content first child not found');
-      emulateSelection(content.firstChild, 5, content.firstChild, 12);
-      const actionBox = diff.querySelector('gr-selection-action-box');
-      if (!actionBox) assert.fail('action box not found');
-      assert.isTrue(actionBox.positionBelow);
-    });
-
-    test('multiline starting on first line', () => {
-      const startContent = stubContent(1, Side.RIGHT);
-      const endContent = stubContent(2, Side.RIGHT);
-      sinon.spy(element, 'positionActionBox');
-      if (!startContent?.firstChild) {
-        assert.fail('first child of start content not found');
-      }
-      if (!endContent?.lastChild) {
-        assert.fail('last child of end content not found');
-      }
-      emulateSelection(startContent.firstChild, 10, endContent.lastChild, 7);
-      const actionBox = diff.querySelector('gr-selection-action-box');
-      if (!actionBox) assert.fail('action box not found');
-      assert.isTrue(actionBox.positionBelow);
-    });
-
-    test('single line', async () => {
-      const content = stubContent(138, Side.LEFT);
-      sinon.spy(element, 'positionActionBox');
-      if (!content?.firstChild) assert.fail('content first child not found');
-      emulateSelection(content.firstChild, 5, content.firstChild, 12);
-      const actionBox = await waitQueryAndAssert<GrSelectionActionBox>(
-        diff,
-        'gr-selection-action-box'
-      );
-      if (!element.selectedRange) assert.fail('no range selected');
-      const {range, side} = element.selectedRange;
-      assert.deepEqual(range, {
-        start_line: 138,
-        start_character: 5,
-        end_line: 138,
-        end_character: 12,
-      });
-      assert.equal(side, Side.LEFT);
-      assert.notOk(actionBox.positionBelow);
-    });
-
-    test('multiline', () => {
-      const startContent = stubContent(119, Side.RIGHT);
-      const endContent = stubContent(120, Side.RIGHT);
-      sinon.spy(element, 'positionActionBox');
-      if (!startContent?.firstChild) {
-        assert.fail('first child of start content not found');
-      }
-      if (!endContent?.lastChild) {
-        assert.fail('last child of end content');
-      }
-      emulateSelection(startContent.firstChild, 10, endContent.lastChild, 7);
-      const actionBox = diff.querySelector('gr-selection-action-box');
-      if (!actionBox) assert.fail('action box not found');
-      if (!element.selectedRange) assert.fail('no range selected');
-      const {range, side} = element.selectedRange;
-      assert.deepEqual(range, {
-        start_line: 119,
-        start_character: 10,
-        end_line: 120,
-        end_character: 36,
-      });
-      assert.equal(side, Side.RIGHT);
-      assert.notOk(actionBox.positionBelow);
-    });
-
-    test('multiple ranges aka firefox implementation', () => {
-      const startContent = stubContent(119, Side.RIGHT);
-      const endContent = stubContent(120, Side.RIGHT);
-      if (!startContent?.firstChild) {
-        assert.fail('first child of start content not found');
-      }
-      if (!endContent?.lastChild) {
-        assert.fail('last child of end content');
-      }
-
-      const startRange = document.createRange();
-      startRange.setStart(startContent.firstChild, 10);
-      startRange.setEnd(startContent.firstChild, 11);
-
-      const endRange = document.createRange();
-      endRange.setStart(endContent.lastChild, 6);
-      endRange.setEnd(endContent.lastChild, 7);
-
-      const getRangeAtStub = sinon.stub();
-      getRangeAtStub
-        .onFirstCall()
-        .returns(startRange)
-        .onSecondCall()
-        .returns(endRange);
-      const selection = {
-        rangeCount: 2,
-        getRangeAt: getRangeAtStub,
-        removeAllRanges: sinon.stub(),
-      } as unknown as Selection;
-      element.handleSelection(selection, false);
-      if (!element.selectedRange) assert.fail('no range selected');
-      const {range} = element.selectedRange;
-      assert.deepEqual(range, {
-        start_line: 119,
-        start_character: 10,
-        end_line: 120,
-        end_character: 36,
-      });
-    });
-
-    test('multiline grow end highlight over tabs', () => {
-      const startContent = stubContent(119, Side.RIGHT);
-      const endContent = stubContent(120, Side.RIGHT);
-      if (!startContent?.firstChild) {
-        assert.fail('first child of start content not found');
-      }
-      if (!endContent?.firstChild) {
-        assert.fail('first child of end content not found');
-      }
-      emulateSelection(startContent.firstChild, 10, endContent.firstChild, 2);
-      if (!element.selectedRange) assert.fail('no range selected');
-      const {range, side} = element.selectedRange;
-      assert.deepEqual(range, {
-        start_line: 119,
-        start_character: 10,
-        end_line: 120,
-        end_character: 2,
-      });
-      assert.equal(side, Side.RIGHT);
-    });
-
-    test('collapsed', () => {
-      const content = stubContent(138, Side.LEFT);
-      if (!content?.firstChild) {
-        assert.fail('first child of content not found');
-      }
-      emulateSelection(content.firstChild, 5, content.firstChild, 5);
-      const sel = document.getSelection();
-      if (!sel) assert.fail('no selection');
-      assert.isOk(sel.getRangeAt(0).startContainer);
-      assert.isFalse(!!element.selectedRange);
-    });
-
-    test('starts inside hl', () => {
-      const content = stubContent(140, Side.LEFT);
-      if (!content) {
-        assert.fail('content not found');
-      }
-      const hl = content.querySelector('.foo');
-      if (!hl?.firstChild) {
-        assert.fail('first child of hl element not found');
-      }
-      if (!hl?.nextSibling) {
-        assert.fail('next sibling of hl element not found');
-      }
-      emulateSelection(hl.firstChild, 2, hl.nextSibling, 7);
-      if (!element.selectedRange) assert.fail('no range selected');
-      const {range, side} = element.selectedRange;
-      assert.deepEqual(range, {
-        start_line: 140,
-        start_character: 8,
-        end_line: 140,
-        end_character: 23,
-      });
-      assert.equal(side, Side.LEFT);
-    });
-
-    test('ends inside hl', () => {
-      const content = stubContent(140, Side.LEFT);
-      if (!content) assert.fail('content not found');
-      const hl = content.querySelector('.bar');
-      if (!hl) assert.fail('hl inside content not found');
-      if (!hl.previousSibling) assert.fail('previous sibling not found');
-      if (!hl.firstChild) assert.fail('first child not found');
-      emulateSelection(hl.previousSibling, 2, hl.firstChild, 3);
-      if (!element.selectedRange) assert.fail('no range selected');
-      const {range} = element.selectedRange;
-      assert.deepEqual(range, {
-        start_line: 140,
-        start_character: 18,
-        end_line: 140,
-        end_character: 27,
-      });
-    });
-
-    test('multiple hl', () => {
-      const content = stubContent(140, Side.LEFT);
-      if (!content) assert.fail('content not found');
-      if (!content.firstChild) assert.fail('first child not found');
-      const hl = content.querySelectorAll('hl')[4];
-      if (!hl) assert.fail('hl not found');
-      if (!hl.firstChild) assert.fail('first child of hl not found');
-      emulateSelection(content.firstChild, 2, hl.firstChild, 2);
-      if (!element.selectedRange) assert.fail('no range selected');
-      const {range, side} = element.selectedRange;
-      assert.deepEqual(range, {
-        start_line: 140,
-        start_character: 2,
-        end_line: 140,
-        end_character: 61,
-      });
-      assert.equal(side, Side.LEFT);
-    });
-
-    test('starts outside of diff', () => {
-      const contentText = stubContent(140, Side.LEFT);
-      if (!contentText) assert.fail('content not found');
-      if (!contentText.firstChild) assert.fail('child not found');
-      const contentTd = contentText.parentElement;
-      if (!contentTd) assert.fail('content td not found');
-      if (!contentTd.parentElement) assert.fail('parent of td not found');
-
-      emulateSelection(contentTd.parentElement, 0, contentText.firstChild, 2);
-      assert.isFalse(!!element.selectedRange);
-    });
-
-    test('ends outside of diff', () => {
-      const content = stubContent(140, Side.LEFT);
-      if (!content) assert.fail('content not found');
-      if (!content.firstChild) assert.fail('child not found');
-      if (!content.nextElementSibling) assert.fail('sibling not found');
-      if (!content.nextElementSibling.firstChild) {
-        assert.fail('sibling child not found');
-      }
-      emulateSelection(
-        content.nextElementSibling.firstChild,
-        2,
-        content.firstChild,
-        2
-      );
-      assert.isFalse(!!element.selectedRange);
-    });
-
-    test('starts and ends on different sides', () => {
-      const startContent = stubContent(140, Side.LEFT);
-      const endContent = stubContent(130, Side.RIGHT);
-      if (!startContent?.firstChild) {
-        assert.fail('first child of start content not found');
-      }
-      if (!endContent?.firstChild) {
-        assert.fail('first child of end content not found');
-      }
-      emulateSelection(startContent.firstChild, 2, endContent.firstChild, 2);
-      assert.isFalse(!!element.selectedRange);
-    });
-
-    test('starts in comment thread element', () => {
-      const startContent = stubContent(140, Side.LEFT);
-      if (!startContent?.parentElement) {
-        assert.fail('parent el of start content not found');
-      }
-      const comment =
-        startContent.parentElement.querySelector('.comment-thread');
-      if (!comment?.firstChild) {
-        assert.fail('first child of comment not found');
-      }
-      const endContent = stubContent(141, Side.LEFT);
-      if (!endContent?.firstChild) {
-        assert.fail('first child of end content not found');
-      }
-      emulateSelection(comment.firstChild, 2, endContent.firstChild, 4);
-      if (!element.selectedRange) assert.fail('no range selected');
-      const {range, side} = element.selectedRange;
-      assert.deepEqual(range, {
-        start_line: 140,
-        start_character: 83,
-        end_line: 141,
-        end_character: 4,
-      });
-      assert.equal(side, Side.LEFT);
-    });
-
-    test('ends in comment thread element', () => {
-      const content = stubContent(140, Side.LEFT);
-      if (!content?.firstChild) {
-        assert.fail('first child of content not found');
-      }
-      if (!content?.parentElement) {
-        assert.fail('parent element of content not found');
-      }
-      const comment = content.parentElement.querySelector('.comment-thread');
-      if (!comment?.firstChild) {
-        assert.fail('first child of comment element not found');
-      }
-      emulateSelection(content.firstChild, 4, comment.firstChild, 1);
-      if (!element.selectedRange) assert.fail('no range selected');
-      const {range, side} = element.selectedRange;
-      assert.deepEqual(range, {
-        start_line: 140,
-        start_character: 4,
-        end_line: 140,
-        end_character: 83,
-      });
-      assert.equal(side, Side.LEFT);
-    });
-
-    test('starts in context element', () => {
-      const contextControl = diff
-        .querySelector('.contextControl')!
-        .querySelector('gr-button');
-      if (!contextControl) assert.fail('context control not found');
-      const content = stubContent(146, Side.RIGHT);
-      if (!content) assert.fail('content not found');
-      if (!content.firstChild) assert.fail('content child not found');
-      emulateSelection(contextControl, 0, content.firstChild, 7);
-      // TODO (viktard): Select nearest line.
-      assert.isFalse(!!element.selectedRange);
-    });
-
-    test('ends in context element', () => {
-      const contextControl = diff
-        .querySelector('.contextControl')!
-        .querySelector('gr-button');
-      if (!contextControl) {
-        assert.fail('context control element not found');
-      }
-      const content = stubContent(141, Side.LEFT);
-      if (!content?.firstChild) {
-        assert.fail('first child of content element not found');
-      }
-      emulateSelection(content.firstChild, 2, contextControl, 1);
-      // TODO (viktard): Select nearest line.
-      assert.isFalse(!!element.selectedRange);
-    });
-
-    test('selection containing context element', () => {
-      const startContent = stubContent(130, Side.RIGHT);
-      const endContent = stubContent(146, Side.RIGHT);
-      if (!startContent?.firstChild) {
-        assert.fail('first child of start content not found');
-      }
-      if (!endContent?.firstChild) {
-        assert.fail('first child of end content not found');
-      }
-      emulateSelection(startContent.firstChild, 3, endContent.firstChild, 14);
-      if (!element.selectedRange) assert.fail('no range selected');
-      const {range, side} = element.selectedRange;
-      assert.deepEqual(range, {
-        start_line: 130,
-        start_character: 3,
-        end_line: 146,
-        end_character: 14,
-      });
-      assert.equal(side, Side.RIGHT);
-    });
-
-    test('ends at a tab', () => {
-      const content = stubContent(140, Side.LEFT);
-      if (!content?.firstChild) {
-        assert.fail('first child of content element not found');
-      }
-      const span = content.querySelector('span');
-      if (!span) assert.fail('span element not found');
-      emulateSelection(content.firstChild, 1, span, 0);
-      if (!element.selectedRange) assert.fail('no range selected');
-      const {range, side} = element.selectedRange;
-      assert.deepEqual(range, {
-        start_line: 140,
-        start_character: 1,
-        end_line: 140,
-        end_character: 51,
-      });
-      assert.equal(side, Side.LEFT);
-    });
-
-    test('starts at a tab', () => {
-      const content = stubContent(140, Side.LEFT);
-      if (!content) assert.fail('content element not found');
-      emulateSelection(
-        content.querySelectorAll('hl')[3],
-        0,
-        content.querySelectorAll('span')[1].nextSibling!,
-        1
-      );
-      if (!element.selectedRange) assert.fail('no range selected');
-      const {range, side} = element.selectedRange;
-      assert.deepEqual(range, {
-        start_line: 140,
-        start_character: 51,
-        end_line: 140,
-        end_character: 71,
-      });
-      assert.equal(side, Side.LEFT);
-    });
-
-    test('properly accounts for syntax highlighting', () => {
-      const content = stubContent(140, Side.LEFT);
-      if (!content) assert.fail('content element not found');
-      emulateSelection(
-        content.querySelectorAll('hl')[3],
-        0,
-        content.querySelectorAll('span')[1],
-        0
-      );
-      if (!element.selectedRange) assert.fail('no range selected');
-      const {range, side} = element.selectedRange;
-      assert.deepEqual(range, {
-        start_line: 140,
-        start_character: 51,
-        end_line: 140,
-        end_character: 69,
-      });
-      assert.equal(side, Side.LEFT);
-    });
-
-    test('GrRangeNormalizer.getTextOffset computes text offset', () => {
-      let content = stubContent(140, Side.LEFT);
-      if (!content) assert.fail('content element not found');
-      if (!content.lastChild) assert.fail('last child of content not found');
-      let child = content.lastChild.lastChild;
-      if (!child) assert.fail('last child of last child of content not found');
-      let result = getTextOffset(content, child);
-      assert.equal(result, 75);
-      content = stubContent(146, Side.RIGHT);
-      if (!content) assert.fail('content element not found');
-      child = content.lastChild;
-      if (!child) assert.fail('child element not found');
-      result = getTextOffset(content, child);
-      assert.equal(result, 0);
-    });
-
-    test('fixTripleClickSelection', () => {
-      const startContent = stubContent(119, Side.RIGHT);
-      const endContent = stubContent(120, Side.RIGHT);
-      if (!startContent?.firstChild) {
-        assert.fail('first child of start content not found');
-      }
-      if (!endContent) assert.fail('end content not found');
-      if (!endContent.firstChild) assert.fail('first child not found');
-      emulateSelection(startContent.firstChild, 0, endContent.firstChild, 0);
-      if (!element.selectedRange) assert.fail('no range selected');
-      const {range, side} = element.selectedRange;
-      assert.deepEqual(range, {
-        start_line: 119,
-        start_character: 0,
-        end_line: 119,
-        end_character: element.getLength(startContent),
-      });
-      assert.equal(side, Side.RIGHT);
-    });
-  });
-});
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff-highlight/gr-range-normalizer.ts b/polygerrit-ui/app/embed/diff-old/gr-diff-highlight/gr-range-normalizer.ts
deleted file mode 100644
index b177e14..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff-highlight/gr-range-normalizer.ts
+++ /dev/null
@@ -1,103 +0,0 @@
-/**
- * @license
- * Copyright 2016 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-
-// Astral code point as per https://mathiasbynens.be/notes/javascript-unicode
-const REGEX_ASTRAL_SYMBOL = /[\uD800-\uDBFF][\uDC00-\uDFFF]/;
-
-export interface NormalizedRange {
-  endContainer: Node;
-  endOffset: number;
-  startContainer: Node;
-  startOffset: number;
-}
-
-/**
- * Remap DOM range to whole lines of a diff if necessary. If the start or
- * end containers are DOM elements that are singular pieces of syntax
- * highlighting, the containers are remapped to the .contentText divs that
- * contain the entire line of code.
- *
- * @param range - the standard DOM selector range.
- * @return A modified version of the range that correctly accounts
- *     for syntax highlighting.
- */
-export function normalize(range: Range): NormalizedRange {
-  const startContainer = getContentTextParent(range.startContainer);
-  const startOffset =
-    range.startOffset + getTextOffset(startContainer, range.startContainer);
-  const endContainer = getContentTextParent(range.endContainer);
-  const endOffset =
-    range.endOffset + getTextOffset(endContainer, range.endContainer);
-  return {
-    startContainer,
-    startOffset,
-    endContainer,
-    endOffset,
-  };
-}
-
-function getContentTextParent(target: Node): Node {
-  if (!target.parentElement) return target;
-
-  let element: Element | null;
-  if (target instanceof Element) {
-    element = target;
-  } else {
-    element = target.parentElement;
-  }
-
-  while (element && !element.classList.contains('contentText')) {
-    if (element.parentElement === null) {
-      return target;
-    }
-    element = element.parentElement;
-  }
-  return element ? element : target;
-}
-
-/**
- * Gets the character offset of the child within the parent.
- * Performs a synchronous in-order traversal from top to bottom of the node
- * element, counting the length of the syntax until child is found.
- *
- * @param node The root DOM element to be searched through.
- * @param child The child element being searched for.
- */
-// TODO(TS): Only export for test.
-export function getTextOffset(node: Node | null, child: Node): number {
-  let count = 0;
-  let stack = [node];
-  while (stack.length) {
-    const n = stack.pop();
-    if (n === child) {
-      break;
-    }
-    if (n?.childNodes && n.childNodes.length !== 0) {
-      const arr = [];
-      for (const childNode of n.childNodes) {
-        arr.push(childNode);
-      }
-      arr.reverse();
-      stack = stack.concat(arr);
-    } else {
-      count += getLength(n);
-    }
-  }
-  return count;
-}
-
-/**
- * The DOM API textContent.length calculation is broken when the text
- * contains Unicode. See https://mathiasbynens.be/notes/javascript-unicode .
- *
- * @param node A text node.
- * @return The length of the text.
- */
-function getLength(node?: Node | null) {
-  return node && node.textContent && node.nodeType !== Node.COMMENT_NODE
-    ? node.textContent.replace(REGEX_ASTRAL_SYMBOL, '_').length
-    : 0;
-}
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff-model/gr-diff-model.ts b/polygerrit-ui/app/embed/diff-old/gr-diff-model/gr-diff-model.ts
deleted file mode 100644
index 7bd2b3d..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff-model/gr-diff-model.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * @license
- * Copyright 2023 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import {Observable} from 'rxjs';
-import {filter} from 'rxjs/operators';
-import {
-  DiffInfo,
-  DiffPreferencesInfo,
-  RenderPreferences,
-} from '../../../api/diff';
-import {define} from '../../../models/dependency';
-import {Model} from '../../../models/base/model';
-import {isDefined} from '../../../types/types';
-import {select} from '../../../utils/observable-util';
-
-export interface DiffState {
-  diff: DiffInfo;
-  path?: string;
-  renderPrefs: RenderPreferences;
-  diffPrefs: DiffPreferencesInfo;
-}
-
-export const diffModelToken = define<DiffModel>('diff-model');
-
-export class DiffModel extends Model<DiffState | undefined> {
-  readonly diff$: Observable<DiffInfo> = select(
-    this.state$.pipe(filter(isDefined)),
-    diffState => diffState.diff
-  );
-
-  readonly path$: Observable<string | undefined> = select(
-    this.state$.pipe(filter(isDefined)),
-    diffState => diffState.path
-  );
-
-  readonly renderPrefs$: Observable<RenderPreferences> = select(
-    this.state$.pipe(filter(isDefined)),
-    diffState => diffState.renderPrefs
-  );
-
-  readonly diffPrefs$: Observable<DiffPreferencesInfo> = select(
-    this.state$.pipe(filter(isDefined)),
-    diffState => diffState.diffPrefs
-  );
-}
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff-processor/gr-diff-processor.ts b/polygerrit-ui/app/embed/diff-old/gr-diff-processor/gr-diff-processor.ts
deleted file mode 100644
index 256dc11..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff-processor/gr-diff-processor.ts
+++ /dev/null
@@ -1,714 +0,0 @@
-/**
- * @license
- * Copyright 2016 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import {GrDiffLine, Highlights} from '../gr-diff/gr-diff-line';
-import {
-  GrDiffGroup,
-  GrDiffGroupType,
-  hideInContextControl,
-} from '../gr-diff/gr-diff-group';
-import {DiffContent} from '../../../types/diff';
-import {Side} from '../../../constants/constants';
-import {debounce, DelayedTask} from '../../../utils/async-util';
-import {assert, assertIsDefined} from '../../../utils/common-util';
-import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
-import {FILE, GrDiffLineType, LOST, LineNumber} from '../../../api/diff';
-
-const WHOLE_FILE = -1;
-
-// visible for testing
-export interface State {
-  lineNums: {
-    left: number;
-    right: number;
-  };
-  chunkIndex: number;
-}
-
-interface ChunkEnd {
-  offset: number;
-  keyLocation: boolean;
-}
-
-export interface KeyLocations {
-  left: {[key: string]: boolean};
-  right: {[key: string]: boolean};
-}
-
-/**
- * The maximum size for an addition or removal chunk before it is broken down
- * into a series of chunks that are this size at most.
- *
- * Note: The value of 120 is chosen so that it is larger than the default
- * asyncThreshold of 64, but feel free to tune this constant to your
- * performance needs.
- */
-function calcMaxGroupSize(asyncThreshold?: number): number {
-  if (!asyncThreshold) return 120;
-  return asyncThreshold * 2;
-}
-
-/** Interface for listening to the output of the processor. */
-export interface GroupConsumer {
-  addGroup(group: GrDiffGroup): void;
-  clearGroups(): void;
-}
-
-/**
- * Converts the API's `DiffContent`s  to `GrDiffGroup`s for rendering.
- *
- * Glossary:
- * - "chunk": A single `DiffContent` as returned by the API.
- * - "group": A single `GrDiffGroup` as used for rendering.
- * - "common" chunk/group: A chunk/group that should be considered unchanged
- *   for diffing purposes. This can mean its either actually unchanged, or it
- *   has only whitespace changes.
- * - "key location": A line number and side of the diff that should not be
- *   collapsed e.g. because a comment is attached to it, or because it was
- *   provided in the URL and thus should be visible
- * - "uncollapsible" chunk/group: A chunk/group that is either not "common",
- *   or cannot be collapsed because it contains a key location
- *
- * Here a a number of tasks this processor performs:
- *  - splitting large chunks to allow more granular async rendering
- *  - adding a group for the "File" pseudo line that file-level comments can
- *    be attached to
- *  - replacing common parts of the diff that are outside the user's
- *    context setting and do not have comments with a group representing the
- *    "expand context" widget. This may require splitting a chunk/group so
- *    that the part that is within the context or has comments is shown, while
- *    the rest is not.
- */
-export class GrDiffProcessor {
-  context = 3;
-
-  consumer?: GroupConsumer;
-
-  keyLocations: KeyLocations = {left: {}, right: {}};
-
-  asyncThreshold = 64;
-
-  // visible for testing
-  isScrolling?: boolean;
-
-  /** Just for making sure that process() is only called once. */
-  private isStarted = false;
-
-  /** Indicates that processing should be stopped. */
-  private isCancelled = false;
-
-  private resetIsScrollingTask?: DelayedTask;
-
-  private readonly handleWindowScroll = () => {
-    this.isScrolling = true;
-    this.resetIsScrollingTask = debounce(
-      this.resetIsScrollingTask,
-      () => (this.isScrolling = false),
-      50
-    );
-  };
-
-  /**
-   * Asynchronously process the diff chunks into groups. As it processes, it
-   * will splice groups into the `groups` property of the component.
-   *
-   * @return A promise that resolves with an
-   * array of GrDiffGroups when the diff is completely processed.
-   */
-  process(chunks: DiffContent[], isBinary: boolean) {
-    assert(this.isStarted === false, 'diff processor cannot be started twice');
-    this.isStarted = true;
-
-    window.addEventListener('scroll', this.handleWindowScroll);
-
-    assertIsDefined(this.consumer, 'consumer');
-    this.consumer.clearGroups();
-    this.consumer.addGroup(this.makeGroup(LOST));
-    this.consumer.addGroup(this.makeGroup(FILE));
-
-    if (isBinary) return Promise.resolve();
-
-    return new Promise<void>(resolve => {
-      const state = {
-        lineNums: {left: 0, right: 0},
-        chunkIndex: 0,
-      };
-
-      chunks = this.splitLargeChunks(chunks);
-      chunks = this.splitCommonChunksWithKeyLocations(chunks);
-
-      let currentBatch = 0;
-      const nextStep = () => {
-        if (this.isCancelled || state.chunkIndex >= chunks.length) {
-          resolve();
-          return;
-        }
-        if (this.isScrolling) {
-          window.setTimeout(nextStep, 100);
-          return;
-        }
-
-        const stateUpdate = this.processNext(state, chunks);
-        for (const group of stateUpdate.groups) {
-          this.consumer?.addGroup(group);
-          currentBatch += group.lines.length;
-        }
-        state.lineNums.left += stateUpdate.lineDelta.left;
-        state.lineNums.right += stateUpdate.lineDelta.right;
-
-        state.chunkIndex = stateUpdate.newChunkIndex;
-        if (currentBatch >= this.asyncThreshold) {
-          currentBatch = 0;
-          window.setTimeout(nextStep, 1);
-        } else {
-          nextStep.call(this);
-        }
-      };
-
-      nextStep.call(this);
-    }).finally(() => {
-      this.finish();
-    });
-  }
-
-  finish() {
-    this.consumer = undefined;
-    window.removeEventListener('scroll', this.handleWindowScroll);
-  }
-
-  cancel() {
-    this.isCancelled = true;
-    this.finish();
-  }
-
-  /**
-   * Process the next uncollapsible chunk, or the next collapsible chunks.
-   */
-  // visible for testing
-  processNext(state: State, chunks: DiffContent[]) {
-    const firstUncollapsibleChunkIndex = this.firstUncollapsibleChunkIndex(
-      chunks,
-      state.chunkIndex
-    );
-    if (firstUncollapsibleChunkIndex === state.chunkIndex) {
-      const chunk = chunks[state.chunkIndex];
-      return {
-        lineDelta: {
-          left: this.linesLeft(chunk).length,
-          right: this.linesRight(chunk).length,
-        },
-        groups: [
-          this.chunkToGroup(
-            chunk,
-            state.lineNums.left + 1,
-            state.lineNums.right + 1
-          ),
-        ],
-        newChunkIndex: state.chunkIndex + 1,
-      };
-    }
-
-    return this.processCollapsibleChunks(
-      state,
-      chunks,
-      firstUncollapsibleChunkIndex
-    );
-  }
-
-  private linesLeft(chunk: DiffContent) {
-    return chunk.ab || chunk.a || [];
-  }
-
-  private linesRight(chunk: DiffContent) {
-    return chunk.ab || chunk.b || [];
-  }
-
-  private firstUncollapsibleChunkIndex(chunks: DiffContent[], offset: number) {
-    let chunkIndex = offset;
-    while (
-      chunkIndex < chunks.length &&
-      this.isCollapsibleChunk(chunks[chunkIndex])
-    ) {
-      chunkIndex++;
-    }
-    return chunkIndex;
-  }
-
-  private isCollapsibleChunk(chunk: DiffContent) {
-    return (chunk.ab || chunk.common || chunk.skip) && !chunk.keyLocation;
-  }
-
-  /**
-   * Process a stretch of collapsible chunks.
-   *
-   * Outputs up to three groups:
-   * 1) Visible context before the hidden common code, unless it's the
-   * very beginning of the file.
-   * 2) Context hidden behind a context bar, unless empty.
-   * 3) Visible context after the hidden common code, unless it's the very
-   * end of the file.
-   */
-  private processCollapsibleChunks(
-    state: State,
-    chunks: DiffContent[],
-    firstUncollapsibleChunkIndex: number
-  ) {
-    const collapsibleChunks = chunks.slice(
-      state.chunkIndex,
-      firstUncollapsibleChunkIndex
-    );
-    const lineCount = collapsibleChunks.reduce(
-      (sum, chunk) => sum + this.commonChunkLength(chunk),
-      0
-    );
-
-    let groups = this.chunksToGroups(
-      collapsibleChunks,
-      state.lineNums.left + 1,
-      state.lineNums.right + 1
-    );
-
-    const hasSkippedGroup = !!groups.find(g => g.skip);
-    if (this.context !== WHOLE_FILE || hasSkippedGroup) {
-      const contextNumLines = this.context > 0 ? this.context : 0;
-      const hiddenStart = state.chunkIndex === 0 ? 0 : contextNumLines;
-      const hiddenEnd =
-        lineCount -
-        (firstUncollapsibleChunkIndex === chunks.length ? 0 : this.context);
-      groups = hideInContextControl(groups, hiddenStart, hiddenEnd);
-    }
-
-    return {
-      lineDelta: {
-        left: lineCount,
-        right: lineCount,
-      },
-      groups,
-      newChunkIndex: firstUncollapsibleChunkIndex,
-    };
-  }
-
-  private commonChunkLength(chunk: DiffContent) {
-    if (chunk.skip) {
-      return chunk.skip;
-    }
-    console.assert(!!chunk.ab || !!chunk.common);
-
-    console.assert(
-      !chunk.a || (!!chunk.b && chunk.a.length === chunk.b.length),
-      'common chunk needs same number of a and b lines: ',
-      chunk
-    );
-    return this.linesLeft(chunk).length;
-  }
-
-  private chunksToGroups(
-    chunks: DiffContent[],
-    offsetLeft: number,
-    offsetRight: number
-  ): GrDiffGroup[] {
-    return chunks.map(chunk => {
-      const group = this.chunkToGroup(chunk, offsetLeft, offsetRight);
-      const chunkLength = this.commonChunkLength(chunk);
-      offsetLeft += chunkLength;
-      offsetRight += chunkLength;
-      return group;
-    });
-  }
-
-  private chunkToGroup(
-    chunk: DiffContent,
-    offsetLeft: number,
-    offsetRight: number
-  ): GrDiffGroup {
-    const type =
-      chunk.ab || chunk.skip ? GrDiffGroupType.BOTH : GrDiffGroupType.DELTA;
-    const lines = this.linesFromChunk(chunk, offsetLeft, offsetRight);
-    const options = {
-      moveDetails: chunk.move_details,
-      dueToRebase: !!chunk.due_to_rebase,
-      ignoredWhitespaceOnly: !!chunk.common,
-      keyLocation: !!chunk.keyLocation,
-    };
-    if (chunk.skip !== undefined) {
-      return new GrDiffGroup({
-        type,
-        skip: chunk.skip,
-        offsetLeft,
-        offsetRight,
-        ...options,
-      });
-    } else {
-      return new GrDiffGroup({
-        type,
-        lines,
-        ...options,
-      });
-    }
-  }
-
-  private linesFromChunk(
-    chunk: DiffContent,
-    offsetLeft: number,
-    offsetRight: number
-  ) {
-    if (chunk.ab) {
-      return chunk.ab.map((row, i) =>
-        this.lineFromRow(GrDiffLineType.BOTH, offsetLeft, offsetRight, row, i)
-      );
-    }
-    let lines: GrDiffLine[] = [];
-    if (chunk.a) {
-      // Avoiding a.push(...b) because that causes callstack overflows for
-      // large b, which can occur when large files are added removed.
-      lines = lines.concat(
-        this.linesFromRows(
-          GrDiffLineType.REMOVE,
-          chunk.a,
-          offsetLeft,
-          chunk.edit_a
-        )
-      );
-    }
-    if (chunk.b) {
-      // Avoiding a.push(...b) because that causes callstack overflows for
-      // large b, which can occur when large files are added removed.
-      lines = lines.concat(
-        this.linesFromRows(
-          GrDiffLineType.ADD,
-          chunk.b,
-          offsetRight,
-          chunk.edit_b
-        )
-      );
-    }
-    return lines;
-  }
-
-  // visible for testing
-  linesFromRows(
-    lineType: GrDiffLineType,
-    rows: string[],
-    offset: number,
-    intralineInfos?: number[][]
-  ): GrDiffLine[] {
-    const grDiffHighlights = intralineInfos
-      ? this.convertIntralineInfos(rows, intralineInfos)
-      : undefined;
-    return rows.map((row, i) =>
-      this.lineFromRow(lineType, offset, offset, row, i, grDiffHighlights)
-    );
-  }
-
-  private lineFromRow(
-    type: GrDiffLineType,
-    offsetLeft: number,
-    offsetRight: number,
-    row: string,
-    i: number,
-    highlights?: Highlights[]
-  ): GrDiffLine {
-    const line = new GrDiffLine(type);
-    line.text = row;
-    if (type !== GrDiffLineType.ADD) line.beforeNumber = offsetLeft + i;
-    if (type !== GrDiffLineType.REMOVE) line.afterNumber = offsetRight + i;
-    if (highlights) {
-      line.hasIntralineInfo = true;
-      line.highlights = highlights.filter(hl => hl.contentIndex === i);
-    } else {
-      line.hasIntralineInfo = false;
-    }
-    return line;
-  }
-
-  private makeGroup(number: LineNumber) {
-    const line = new GrDiffLine(GrDiffLineType.BOTH);
-    line.beforeNumber = number;
-    line.afterNumber = number;
-    return new GrDiffGroup({type: GrDiffGroupType.BOTH, lines: [line]});
-  }
-
-  /**
-   * Split chunks into smaller chunks of the same kind.
-   *
-   * This is done to prevent doing too much work on the main thread in one
-   * uninterrupted rendering step, which would make the browser unresponsive.
-   *
-   * Note that in the case of unmodified chunks, we only split chunks if the
-   * context is set to file (because otherwise they are split up further down
-   * the processing into the visible and hidden context), and only split it
-   * into 2 chunks, one max sized one and the rest (for reasons that are
-   * unclear to me).
-   *
-   * @param chunks Chunks as returned from the server
-   * @return Finer grained chunks.
-   */
-  // visible for testing
-  splitLargeChunks(chunks: DiffContent[]): DiffContent[] {
-    const newChunks = [];
-
-    for (const chunk of chunks) {
-      if (!chunk.ab) {
-        for (const subChunk of this.breakdownChunk(chunk)) {
-          newChunks.push(subChunk);
-        }
-        continue;
-      }
-
-      // If the context is set to "whole file", then break down the shared
-      // chunks so they can be rendered incrementally. Note: this is not
-      // enabled for any other context preference because manipulating the
-      // chunks in this way violates assumptions by the context grouper logic.
-      const MAX_GROUP_SIZE = calcMaxGroupSize(this.asyncThreshold);
-      if (this.context === -1 && chunk.ab.length > MAX_GROUP_SIZE * 2) {
-        // Split large shared chunks in two, where the first is the maximum
-        // group size.
-        newChunks.push({ab: chunk.ab.slice(0, MAX_GROUP_SIZE)});
-        newChunks.push({ab: chunk.ab.slice(MAX_GROUP_SIZE)});
-      } else {
-        newChunks.push(chunk);
-      }
-    }
-    return newChunks;
-  }
-
-  /**
-   * In order to show key locations, such as comments, out of the bounds of
-   * the selected context, treat them as separate chunks within the model so
-   * that the content (and context surrounding it) renders correctly.
-   *
-   * @param chunks DiffContents as returned from server.
-   * @return Finer grained DiffContents.
-   */
-  // visible for testing
-  splitCommonChunksWithKeyLocations(chunks: DiffContent[]): DiffContent[] {
-    const result = [];
-    let leftLineNum = 1;
-    let rightLineNum = 1;
-
-    for (const chunk of chunks) {
-      // If it isn't a common chunk, append it as-is and update line numbers.
-      if (!chunk.ab && !chunk.skip && !chunk.common) {
-        if (chunk.a) {
-          leftLineNum += chunk.a.length;
-        }
-        if (chunk.b) {
-          rightLineNum += chunk.b.length;
-        }
-        result.push(chunk);
-        continue;
-      }
-
-      if (chunk.common && chunk.a!.length !== chunk.b!.length) {
-        throw new Error(
-          'DiffContent with common=true must always have equal length'
-        );
-      }
-      const numLines = this.commonChunkLength(chunk);
-      const chunkEnds = this.findChunkEndsAtKeyLocations(
-        numLines,
-        leftLineNum,
-        rightLineNum
-      );
-      leftLineNum += numLines;
-      rightLineNum += numLines;
-
-      if (chunk.skip) {
-        result.push({
-          ...chunk,
-          skip: chunk.skip,
-          keyLocation: false,
-        });
-      } else if (chunk.ab) {
-        result.push(
-          ...this.splitAtChunkEnds(chunk.ab, chunkEnds).map(
-            ({lines, keyLocation}) => {
-              return {
-                ...chunk,
-                ab: lines,
-                keyLocation,
-              };
-            }
-          )
-        );
-      } else if (chunk.common) {
-        const aChunks = this.splitAtChunkEnds(chunk.a!, chunkEnds);
-        const bChunks = this.splitAtChunkEnds(chunk.b!, chunkEnds);
-        result.push(
-          ...aChunks.map(({lines, keyLocation}, i) => {
-            return {
-              ...chunk,
-              a: lines,
-              b: bChunks[i].lines,
-              keyLocation,
-            };
-          })
-        );
-      }
-    }
-
-    return result;
-  }
-
-  /**
-   * @return Offsets of the new chunk ends, including whether it's a key
-   * location.
-   */
-  private findChunkEndsAtKeyLocations(
-    numLines: number,
-    leftOffset: number,
-    rightOffset: number
-  ): ChunkEnd[] {
-    const result = [];
-    let lastChunkEnd = 0;
-    for (let i = 0; i < numLines; i++) {
-      // If this line should not be collapsed.
-      if (
-        this.keyLocations[Side.LEFT][leftOffset + i] ||
-        this.keyLocations[Side.RIGHT][rightOffset + i]
-      ) {
-        // If any lines have been accumulated into the chunk leading up to
-        // this non-collapse line, then add them as a chunk and start a new
-        // one.
-        if (i > lastChunkEnd) {
-          result.push({offset: i, keyLocation: false});
-          lastChunkEnd = i;
-        }
-
-        // Add the non-collapse line as its own chunk.
-        result.push({offset: i + 1, keyLocation: true});
-      }
-    }
-
-    if (numLines > lastChunkEnd) {
-      result.push({offset: numLines, keyLocation: false});
-    }
-
-    return result;
-  }
-
-  private splitAtChunkEnds(lines: string[], chunkEnds: ChunkEnd[]) {
-    const result = [];
-    let lastChunkEndOffset = 0;
-    for (const {offset, keyLocation} of chunkEnds) {
-      if (lastChunkEndOffset === offset) continue;
-      result.push({
-        lines: lines.slice(lastChunkEndOffset, offset),
-        keyLocation,
-      });
-      lastChunkEndOffset = offset;
-    }
-    return result;
-  }
-
-  /**
-   * Converts `IntralineInfo`s return by the API to `GrLineHighlights` used
-   * for rendering.
-   */
-  // visible for testing
-  convertIntralineInfos(
-    rows: string[],
-    intralineInfos: number[][]
-  ): Highlights[] {
-    // +1 to account for the \n that is not part of the rows passed here
-    const lineLengths = rows.map(r => GrAnnotation.getStringLength(r) + 1);
-
-    let rowIndex = 0;
-    let idx = 0;
-    const normalized = [];
-    for (const [skipLength, markLength] of intralineInfos) {
-      let lineLength = lineLengths[rowIndex];
-      let j = 0;
-      while (j < skipLength) {
-        if (idx === lineLength) {
-          idx = 0;
-          lineLength = lineLengths[++rowIndex];
-          continue;
-        }
-        idx++;
-        j++;
-      }
-      let lineHighlight: Highlights = {
-        contentIndex: rowIndex,
-        startIndex: idx,
-      };
-
-      j = 0;
-      while (lineLength && j < markLength) {
-        if (idx === lineLength) {
-          idx = 0;
-          lineLength = lineLengths[++rowIndex];
-          normalized.push(lineHighlight);
-          lineHighlight = {
-            contentIndex: rowIndex,
-            startIndex: idx,
-          };
-          continue;
-        }
-        idx++;
-        j++;
-      }
-      lineHighlight.endIndex = idx;
-      normalized.push(lineHighlight);
-    }
-    return normalized;
-  }
-
-  /**
-   * If a group is an addition or a removal, break it down into smaller groups
-   * of that type using the MAX_GROUP_SIZE. If the group is a shared chunk
-   * or a delta it is returned as the single element of the result array.
-   */
-  // visible for testing
-  breakdownChunk(chunk: DiffContent): DiffContent[] {
-    let key: 'a' | 'b' | 'ab' | null = null;
-    const {a, b, ab, move_details} = chunk;
-    if (a?.length && !b?.length) {
-      key = 'a';
-    } else if (b?.length && !a?.length) {
-      key = 'b';
-    } else if (ab?.length) {
-      key = 'ab';
-    }
-
-    // Move chunks should not be divided because of move label
-    // positioned in the top of the chunk
-    if (!key || move_details) {
-      return [chunk];
-    }
-
-    const MAX_GROUP_SIZE = calcMaxGroupSize(this.asyncThreshold);
-    return this.breakdown(chunk[key]!, MAX_GROUP_SIZE).map(subChunkLines => {
-      const subChunk: DiffContent = {};
-      subChunk[key!] = subChunkLines;
-      if (chunk.due_to_rebase) {
-        subChunk.due_to_rebase = true;
-      }
-      if (chunk.move_details) {
-        subChunk.move_details = chunk.move_details;
-      }
-      return subChunk;
-    });
-  }
-
-  /**
-   * Given an array and a size, return an array of arrays where no inner array
-   * is larger than that size, preserving the original order.
-   */
-  // visible for testing
-  breakdown<T>(array: T[], size: number): T[][] {
-    if (!array.length) {
-      return [];
-    }
-    if (array.length < size) {
-      return [array];
-    }
-
-    const head = array.slice(0, array.length - size);
-    const tail = array.slice(array.length - size);
-
-    return this.breakdown(head, size).concat([tail]);
-  }
-}
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff-processor/gr-diff-processor_test.ts b/polygerrit-ui/app/embed/diff-old/gr-diff-processor/gr-diff-processor_test.ts
deleted file mode 100644
index 335f0d0..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff-processor/gr-diff-processor_test.ts
+++ /dev/null
@@ -1,1136 +0,0 @@
-/**
- * @license
- * Copyright 2016 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import '../../../test/common-test-setup';
-import './gr-diff-processor';
-import {GrDiffLine} from '../gr-diff/gr-diff-line';
-import {GrDiffGroup, GrDiffGroupType} from '../gr-diff/gr-diff-group';
-import {GrDiffProcessor, State} from './gr-diff-processor';
-import {DiffContent} from '../../../types/diff';
-import {assert} from '@open-wc/testing';
-import {FILE, GrDiffLineType} from '../../../api/diff';
-
-suite('gr-diff-processor tests', () => {
-  const WHOLE_FILE = -1;
-  const loremIpsum =
-    'Lorem ipsum dolor sit amet, ei nonumes vituperata ius. ' +
-    'Duo  animal omnesque fabellas et. Id has phaedrum dignissim ' +
-    'deterruisset, pro ei petentium comprehensam, ut vis solum dicta. ' +
-    'Eos cu aliquam labores qualisque, usu postea inermis te, et solum ' +
-    'fugit assum per.';
-
-  let element: GrDiffProcessor;
-  let groups: GrDiffGroup[];
-
-  setup(() => {});
-
-  suite('not logged in', () => {
-    setup(() => {
-      groups = [];
-      element = new GrDiffProcessor();
-      element.consumer = {
-        addGroup(group: GrDiffGroup) {
-          groups.push(group);
-        },
-        clearGroups() {
-          groups = [];
-        },
-      };
-      element.context = 4;
-    });
-
-    test('process loaded content', () => {
-      const content: DiffContent[] = [
-        {
-          ab: ['<!DOCTYPE html>', '<meta charset="utf-8">'],
-        },
-        {
-          a: ['  Welcome ', '  to the wooorld of tomorrow!'],
-          b: ['  Hello, world!'],
-        },
-        {
-          ab: [
-            'Leela: This is the only place the ship can’t hear us, so ',
-            'everyone pretend to shower.',
-            'Fry: Same as every day. Got it.',
-          ],
-        },
-      ];
-
-      return element.process(content, false).then(() => {
-        groups.shift(); // remove portedThreadsWithoutRangeGroup
-        assert.equal(groups.length, 4);
-
-        let group = groups[0];
-        assert.equal(group.type, GrDiffGroupType.BOTH);
-        assert.equal(group.lines.length, 1);
-        assert.equal(group.lines[0].text, '');
-        assert.equal(group.lines[0].beforeNumber, FILE);
-        assert.equal(group.lines[0].afterNumber, FILE);
-
-        group = groups[1];
-        assert.equal(group.type, GrDiffGroupType.BOTH);
-        assert.equal(group.lines.length, 2);
-
-        function beforeNumberFn(l: GrDiffLine) {
-          return l.beforeNumber;
-        }
-        function afterNumberFn(l: GrDiffLine) {
-          return l.afterNumber;
-        }
-        function textFn(l: GrDiffLine) {
-          return l.text;
-        }
-
-        assert.deepEqual(group.lines.map(beforeNumberFn), [1, 2]);
-        assert.deepEqual(group.lines.map(afterNumberFn), [1, 2]);
-        assert.deepEqual(group.lines.map(textFn), [
-          '<!DOCTYPE html>',
-          '<meta charset="utf-8">',
-        ]);
-
-        group = groups[2];
-        assert.equal(group.type, GrDiffGroupType.DELTA);
-        assert.equal(group.lines.length, 3);
-        assert.equal(group.adds.length, 1);
-        assert.equal(group.removes.length, 2);
-        assert.deepEqual(group.removes.map(beforeNumberFn), [3, 4]);
-        assert.deepEqual(group.adds.map(afterNumberFn), [3]);
-        assert.deepEqual(group.removes.map(textFn), [
-          '  Welcome ',
-          '  to the wooorld of tomorrow!',
-        ]);
-        assert.deepEqual(group.adds.map(textFn), ['  Hello, world!']);
-
-        group = groups[3];
-        assert.equal(group.type, GrDiffGroupType.BOTH);
-        assert.equal(group.lines.length, 3);
-        assert.deepEqual(group.lines.map(beforeNumberFn), [5, 6, 7]);
-        assert.deepEqual(group.lines.map(afterNumberFn), [4, 5, 6]);
-        assert.deepEqual(group.lines.map(textFn), [
-          'Leela: This is the only place the ship can’t hear us, so ',
-          'everyone pretend to shower.',
-          'Fry: Same as every day. Got it.',
-        ]);
-      });
-    });
-
-    test('first group is for file', () => {
-      const content = [{b: ['foo']}];
-
-      return element.process(content, false).then(() => {
-        groups.shift(); // remove portedThreadsWithoutRangeGroup
-
-        assert.equal(groups[0].type, GrDiffGroupType.BOTH);
-        assert.equal(groups[0].lines.length, 1);
-        assert.equal(groups[0].lines[0].text, '');
-        assert.equal(groups[0].lines[0].beforeNumber, FILE);
-        assert.equal(groups[0].lines[0].afterNumber, FILE);
-      });
-    });
-
-    suite('context groups', () => {
-      test('at the beginning, larger than context', () => {
-        element.context = 10;
-        const content = [
-          {
-            ab: Array.from<string>({length: 100}).fill(
-              'all work and no play make jack a dull boy'
-            ),
-          },
-          {a: ['all work and no play make andybons a dull boy']},
-        ];
-
-        return element.process(content, false).then(() => {
-          groups.shift(); // remove portedThreadsWithoutRangeGroup
-
-          // group[0] is the file group
-
-          assert.equal(groups[1].type, GrDiffGroupType.CONTEXT_CONTROL);
-          assert.instanceOf(groups[1].contextGroups[0], GrDiffGroup);
-          assert.equal(groups[1].contextGroups[0].lines.length, 90);
-          for (const l of groups[1].contextGroups[0].lines) {
-            assert.equal(l.text, 'all work and no play make jack a dull boy');
-          }
-
-          assert.equal(groups[2].type, GrDiffGroupType.BOTH);
-          assert.equal(groups[2].lines.length, 10);
-          for (const l of groups[2].lines) {
-            assert.equal(l.text, 'all work and no play make jack a dull boy');
-          }
-        });
-      });
-
-      test('at the beginning with skip chunks', async () => {
-        element.context = 10;
-        const content = [
-          {
-            ab: Array.from<string>({length: 20}).fill(
-              'all work and no play make jack a dull boy'
-            ),
-          },
-          {skip: 43900},
-          {ab: Array.from<string>({length: 30}).fill('some other content')},
-          {a: ['some other content']},
-        ];
-
-        await element.process(content, false);
-
-        groups.shift(); // remove portedThreadsWithoutRangeGroup
-
-        // group[0] is the file group
-
-        const commonGroup = groups[1];
-
-        // Hidden context before
-        assert.equal(commonGroup.type, GrDiffGroupType.CONTEXT_CONTROL);
-        assert.instanceOf(commonGroup.contextGroups[0], GrDiffGroup);
-        assert.equal(commonGroup.contextGroups[0].lines.length, 20);
-        for (const l of commonGroup.contextGroups[0].lines) {
-          assert.equal(l.text, 'all work and no play make jack a dull boy');
-        }
-
-        // Skipped group
-        const skipGroup = commonGroup.contextGroups[1];
-        assert.equal(skipGroup.skip, 43900);
-        const expectedRange = {
-          left: {start_line: 21, end_line: 43920},
-          right: {start_line: 21, end_line: 43920},
-        };
-        assert.deepEqual(skipGroup.lineRange, expectedRange);
-
-        // Hidden context after
-        assert.equal(commonGroup.contextGroups[2].lines.length, 20);
-        for (const l of commonGroup.contextGroups[2].lines) {
-          assert.equal(l.text, 'some other content');
-        }
-
-        // Displayed lines
-        assert.equal(groups[2].type, GrDiffGroupType.BOTH);
-        assert.equal(groups[2].lines.length, 10);
-        for (const l of groups[2].lines) {
-          assert.equal(l.text, 'some other content');
-        }
-      });
-
-      test('at the beginning, smaller than context', () => {
-        element.context = 10;
-        const content = [
-          {
-            ab: Array.from<string>({length: 5}).fill(
-              'all work and no play make jack a dull boy'
-            ),
-          },
-          {a: ['all work and no play make andybons a dull boy']},
-        ];
-
-        return element.process(content, false).then(() => {
-          groups.shift(); // remove portedThreadsWithoutRangeGroup
-
-          // group[0] is the file group
-
-          assert.equal(groups[1].type, GrDiffGroupType.BOTH);
-          assert.equal(groups[1].lines.length, 5);
-          for (const l of groups[1].lines) {
-            assert.equal(l.text, 'all work and no play make jack a dull boy');
-          }
-        });
-      });
-
-      test('at the end, larger than context', () => {
-        element.context = 10;
-        const content = [
-          {a: ['all work and no play make andybons a dull boy']},
-          {
-            ab: Array.from<string>({length: 100}).fill(
-              'all work and no play make jill a dull girl'
-            ),
-          },
-        ];
-
-        return element.process(content, false).then(() => {
-          groups.shift(); // remove portedThreadsWithoutRangeGroup
-
-          // group[0] is the file group
-          // group[1] is the "a" group
-
-          assert.equal(groups[2].type, GrDiffGroupType.BOTH);
-          assert.equal(groups[2].lines.length, 10);
-          for (const l of groups[2].lines) {
-            assert.equal(l.text, 'all work and no play make jill a dull girl');
-          }
-
-          assert.equal(groups[3].type, GrDiffGroupType.CONTEXT_CONTROL);
-          assert.instanceOf(groups[3].contextGroups[0], GrDiffGroup);
-          assert.equal(groups[3].contextGroups[0].lines.length, 90);
-          for (const l of groups[3].contextGroups[0].lines) {
-            assert.equal(l.text, 'all work and no play make jill a dull girl');
-          }
-        });
-      });
-
-      test('at the end, smaller than context', () => {
-        element.context = 10;
-        const content = [
-          {a: ['all work and no play make andybons a dull boy']},
-          {
-            ab: Array.from<string>({length: 5}).fill(
-              'all work and no play make jill a dull girl'
-            ),
-          },
-        ];
-
-        return element.process(content, false).then(() => {
-          groups.shift(); // remove portedThreadsWithoutRangeGroup
-
-          // group[0] is the file group
-          // group[1] is the "a" group
-
-          assert.equal(groups[2].type, GrDiffGroupType.BOTH);
-          assert.equal(groups[2].lines.length, 5);
-          for (const l of groups[2].lines) {
-            assert.equal(l.text, 'all work and no play make jill a dull girl');
-          }
-        });
-      });
-
-      test('for interleaved ab and common: true chunks', () => {
-        element.context = 10;
-        const content = [
-          {a: ['all work and no play make andybons a dull boy']},
-          {
-            ab: Array.from<string>({length: 3}).fill(
-              'all work and no play make jill a dull girl'
-            ),
-          },
-          {
-            a: Array.from<string>({length: 3}).fill(
-              'all work and no play make jill a dull girl'
-            ),
-            b: Array.from<string>({length: 3}).fill(
-              '  all work and no play make jill a dull girl'
-            ),
-            common: true,
-          },
-          {
-            ab: Array.from<string>({length: 3}).fill(
-              'all work and no play make jill a dull girl'
-            ),
-          },
-          {
-            a: Array.from<string>({length: 3}).fill(
-              'all work and no play make jill a dull girl'
-            ),
-            b: Array.from<string>({length: 3}).fill(
-              '  all work and no play make jill a dull girl'
-            ),
-            common: true,
-          },
-          {
-            ab: Array.from<string>({length: 3}).fill(
-              'all work and no play make jill a dull girl'
-            ),
-          },
-        ];
-
-        return element.process(content, false).then(() => {
-          groups.shift(); // remove portedThreadsWithoutRangeGroup
-
-          // group[0] is the file group
-          // group[1] is the "a" group
-
-          // The first three interleaved chunks are completely shown because
-          // they are part of the context (3 * 3 <= 10)
-
-          assert.equal(groups[2].type, GrDiffGroupType.BOTH);
-          assert.equal(groups[2].lines.length, 3);
-          for (const l of groups[2].lines) {
-            assert.equal(l.text, 'all work and no play make jill a dull girl');
-          }
-
-          assert.equal(groups[3].type, GrDiffGroupType.DELTA);
-          assert.equal(groups[3].lines.length, 6);
-          assert.equal(groups[3].adds.length, 3);
-          assert.equal(groups[3].removes.length, 3);
-          for (const l of groups[3].removes) {
-            assert.equal(l.text, 'all work and no play make jill a dull girl');
-          }
-          for (const l of groups[3].adds) {
-            assert.equal(
-              l.text,
-              '  all work and no play make jill a dull girl'
-            );
-          }
-
-          assert.equal(groups[4].type, GrDiffGroupType.BOTH);
-          assert.equal(groups[4].lines.length, 3);
-          for (const l of groups[4].lines) {
-            assert.equal(l.text, 'all work and no play make jill a dull girl');
-          }
-
-          // The next chunk is partially shown, so it results in two groups
-
-          assert.equal(groups[5].type, GrDiffGroupType.DELTA);
-          assert.equal(groups[5].lines.length, 2);
-          assert.equal(groups[5].adds.length, 1);
-          assert.equal(groups[5].removes.length, 1);
-          for (const l of groups[5].removes) {
-            assert.equal(l.text, 'all work and no play make jill a dull girl');
-          }
-          for (const l of groups[5].adds) {
-            assert.equal(
-              l.text,
-              '  all work and no play make jill a dull girl'
-            );
-          }
-
-          assert.equal(groups[6].type, GrDiffGroupType.CONTEXT_CONTROL);
-          assert.equal(groups[6].contextGroups.length, 2);
-
-          assert.equal(groups[6].contextGroups[0].lines.length, 4);
-          assert.equal(groups[6].contextGroups[0].removes.length, 2);
-          assert.equal(groups[6].contextGroups[0].adds.length, 2);
-          for (const l of groups[6].contextGroups[0].removes) {
-            assert.equal(l.text, 'all work and no play make jill a dull girl');
-          }
-          for (const l of groups[6].contextGroups[0].adds) {
-            assert.equal(
-              l.text,
-              '  all work and no play make jill a dull girl'
-            );
-          }
-
-          // The final chunk is completely hidden
-          assert.equal(groups[6].contextGroups[1].type, GrDiffGroupType.BOTH);
-          assert.equal(groups[6].contextGroups[1].lines.length, 3);
-          for (const l of groups[6].contextGroups[1].lines) {
-            assert.equal(l.text, 'all work and no play make jill a dull girl');
-          }
-        });
-      });
-
-      test('in the middle, larger than context', () => {
-        element.context = 10;
-        const content = [
-          {a: ['all work and no play make andybons a dull boy']},
-          {
-            ab: Array.from<string>({length: 100}).fill(
-              'all work and no play make jill a dull girl'
-            ),
-          },
-          {a: ['all work and no play make andybons a dull boy']},
-        ];
-
-        return element.process(content, false).then(() => {
-          groups.shift(); // remove portedThreadsWithoutRangeGroup
-
-          // group[0] is the file group
-          // group[1] is the "a" group
-
-          assert.equal(groups[2].type, GrDiffGroupType.BOTH);
-          assert.equal(groups[2].lines.length, 10);
-          for (const l of groups[2].lines) {
-            assert.equal(l.text, 'all work and no play make jill a dull girl');
-          }
-
-          assert.equal(groups[3].type, GrDiffGroupType.CONTEXT_CONTROL);
-          assert.instanceOf(groups[3].contextGroups[0], GrDiffGroup);
-          assert.equal(groups[3].contextGroups[0].lines.length, 80);
-          for (const l of groups[3].contextGroups[0].lines) {
-            assert.equal(l.text, 'all work and no play make jill a dull girl');
-          }
-
-          assert.equal(groups[4].type, GrDiffGroupType.BOTH);
-          assert.equal(groups[4].lines.length, 10);
-          for (const l of groups[4].lines) {
-            assert.equal(l.text, 'all work and no play make jill a dull girl');
-          }
-        });
-      });
-
-      test('in the middle, smaller than context', () => {
-        element.context = 10;
-        const content = [
-          {a: ['all work and no play make andybons a dull boy']},
-          {
-            ab: Array.from<string>({length: 5}).fill(
-              'all work and no play make jill a dull girl'
-            ),
-          },
-          {a: ['all work and no play make andybons a dull boy']},
-        ];
-
-        return element.process(content, false).then(() => {
-          groups.shift(); // remove portedThreadsWithoutRangeGroup
-
-          // group[0] is the file group
-          // group[1] is the "a" group
-
-          assert.equal(groups[2].type, GrDiffGroupType.BOTH);
-          assert.equal(groups[2].lines.length, 5);
-          for (const l of groups[2].lines) {
-            assert.equal(l.text, 'all work and no play make jill a dull girl');
-          }
-        });
-      });
-    });
-
-    test('in the middle with skip chunks', async () => {
-      element.context = 10;
-      const content = [
-        {a: ['all work and no play make andybons a dull boy']},
-        {
-          ab: Array.from<string>({length: 20}).fill(
-            'all work and no play make jill a dull girl'
-          ),
-        },
-        {skip: 60},
-        {
-          ab: Array.from<string>({length: 20}).fill(
-            'all work and no play make jill a dull girl'
-          ),
-        },
-        {a: ['all work and no play make andybons a dull boy']},
-      ];
-
-      await element.process(content, false);
-
-      groups.shift(); // remove portedThreadsWithoutRangeGroup
-
-      // group[0] is the file group
-      // group[1] is the chunk with a
-      // group[2] is the displayed part of ab before
-
-      const commonGroup = groups[3];
-
-      // Hidden context before
-      assert.equal(commonGroup.type, GrDiffGroupType.CONTEXT_CONTROL);
-      assert.instanceOf(commonGroup.contextGroups[0], GrDiffGroup);
-      assert.equal(commonGroup.contextGroups[0].lines.length, 10);
-      for (const l of commonGroup.contextGroups[0].lines) {
-        assert.equal(l.text, 'all work and no play make jill a dull girl');
-      }
-
-      // Skipped group
-      const skipGroup = commonGroup.contextGroups[1];
-      assert.equal(skipGroup.skip, 60);
-      const expectedRange = {
-        left: {start_line: 22, end_line: 81},
-        right: {start_line: 21, end_line: 80},
-      };
-      assert.deepEqual(skipGroup.lineRange, expectedRange);
-
-      // Hidden context after
-      assert.equal(commonGroup.contextGroups[2].lines.length, 10);
-      for (const l of commonGroup.contextGroups[2].lines) {
-        assert.equal(l.text, 'all work and no play make jill a dull girl');
-      }
-      // group[4] is the displayed part of the second ab
-    });
-
-    test('works with skip === 0', async () => {
-      element.context = 3;
-      const content = [
-        {
-          skip: 0,
-        },
-        {
-          b: [
-            '/**',
-            ' * @license',
-            ' * Copyright 2015 Google LLC',
-            ' * SPDX-License-Identifier: Apache-2.0',
-            ' */',
-            "import '../../../test/common-test-setup';",
-          ],
-        },
-      ];
-      await element.process(content, false);
-    });
-
-    test('break up common diff chunks', () => {
-      element.keyLocations = {
-        left: {1: true},
-        right: {10: true},
-      };
-
-      const content = [
-        {
-          ab: [
-            'copy',
-            '',
-            'asdf',
-            'qwer',
-            'zxcv',
-            '',
-            'http',
-            '',
-            'vbnm',
-            'dfgh',
-            'yuio',
-            'sdfg',
-            '1234',
-          ],
-        },
-      ];
-      const result = element.splitCommonChunksWithKeyLocations(content);
-      assert.deepEqual(result, [
-        {
-          ab: ['copy'],
-          keyLocation: true,
-        },
-        {
-          ab: ['', 'asdf', 'qwer', 'zxcv', '', 'http', '', 'vbnm'],
-          keyLocation: false,
-        },
-        {
-          ab: ['dfgh'],
-          keyLocation: true,
-        },
-        {
-          ab: ['yuio', 'sdfg', '1234'],
-          keyLocation: false,
-        },
-      ]);
-    });
-
-    test('breaks down shared chunks w/ whole-file', () => {
-      const maxGroupSize = 128;
-      const size = maxGroupSize * 2 + 5;
-      const ab = Array(size)
-        .fill(0)
-        .map(() => `${Math.random()}`);
-      const content = [{ab}];
-      element.context = -1;
-      const result = element.splitLargeChunks(content);
-      assert.equal(result.length, 2);
-      assert.deepEqual(result[0].ab, content[0].ab.slice(0, maxGroupSize));
-      assert.deepEqual(result[1].ab, content[0].ab.slice(maxGroupSize));
-    });
-
-    test('breaks down added chunks', () => {
-      const maxGroupSize = 128;
-      const size = maxGroupSize * 2 + 5;
-      const content = Array(size)
-        .fill(0)
-        .map(() => `${Math.random()}`);
-      element.context = 5;
-      const splitContent = element
-        .splitLargeChunks([{a: [], b: content}])
-        .map(r => r.b);
-      assert.equal(splitContent.length, 3);
-      assert.deepEqual(splitContent[0], content.slice(0, 5));
-      assert.deepEqual(splitContent[1], content.slice(5, maxGroupSize + 5));
-      assert.deepEqual(splitContent[2], content.slice(maxGroupSize + 5));
-    });
-
-    test('breaks down removed chunks', () => {
-      const maxGroupSize = 128;
-      const size = maxGroupSize * 2 + 5;
-      const content = Array(size)
-        .fill(0)
-        .map(() => `${Math.random()}`);
-      element.context = 5;
-      const splitContent = element
-        .splitLargeChunks([{a: content, b: []}])
-        .map(r => r.a);
-      assert.equal(splitContent.length, 3);
-      assert.deepEqual(splitContent[0], content.slice(0, 5));
-      assert.deepEqual(splitContent[1], content.slice(5, maxGroupSize + 5));
-      assert.deepEqual(splitContent[2], content.slice(maxGroupSize + 5));
-    });
-
-    test('does not break down moved chunks', () => {
-      const size = 120 * 2 + 5;
-      const content = Array(size)
-        .fill(0)
-        .map(() => `${Math.random()}`);
-      element.context = 5;
-      const splitContent = element
-        .splitLargeChunks([
-          {
-            a: content,
-            b: [],
-            move_details: {changed: false, range: {start: 1, end: 1}},
-          },
-        ])
-        .map(r => r.a);
-      assert.equal(splitContent.length, 1);
-      assert.deepEqual(splitContent[0], content);
-    });
-
-    test('does not break-down common chunks w/ context', () => {
-      const ab = Array(75)
-        .fill(0)
-        .map(() => `${Math.random()}`);
-      const content = [{ab}];
-      element.context = 4;
-      const result = element.splitCommonChunksWithKeyLocations(content);
-      assert.equal(result.length, 1);
-      assert.deepEqual(result[0].ab, content[0].ab);
-      assert.isFalse(result[0].keyLocation);
-    });
-
-    test('intraline normalization', () => {
-      // The content and highlights are in the format returned by the Gerrit
-      // REST API.
-      let content = [
-        '      <section class="summary">',
-        '        <gr-formatted-text content="' +
-          '[[_computeCurrentRevisionMessage(change)]]"></gr-formatted-text>',
-        '      </section>',
-      ];
-      let highlights = [
-        [31, 34],
-        [42, 26],
-      ];
-
-      let results = element.convertIntralineInfos(content, highlights);
-      assert.deepEqual(results, [
-        {
-          contentIndex: 0,
-          startIndex: 31,
-        },
-        {
-          contentIndex: 1,
-          startIndex: 0,
-          endIndex: 33,
-        },
-        {
-          contentIndex: 1,
-          endIndex: 101,
-          startIndex: 75,
-        },
-      ]);
-      const lines = element.linesFromRows(
-        GrDiffLineType.BOTH,
-        content,
-        0,
-        highlights
-      );
-      assert.equal(lines.length, 3);
-      assert.isTrue(lines[0].hasIntralineInfo);
-      assert.equal(lines[0].highlights.length, 1);
-      assert.isTrue(lines[1].hasIntralineInfo);
-      assert.equal(lines[1].highlights.length, 2);
-      assert.isTrue(lines[2].hasIntralineInfo);
-      assert.equal(lines[2].highlights.length, 0);
-
-      content = [
-        '        this._path = value.path;',
-        '',
-        '        // When navigating away from the page, there is a ' +
-          'possibility that the',
-        '        // patch number is no longer a part of the URL ' +
-          '(say when navigating to',
-        '        // the top-level change info view) and therefore ' +
-          'undefined in `params`.',
-        '        if (!this._patchRange.patchNum) {',
-      ];
-      highlights = [
-        [14, 17],
-        [11, 70],
-        [12, 67],
-        [12, 67],
-        [14, 29],
-      ];
-      results = element.convertIntralineInfos(content, highlights);
-      assert.deepEqual(results, [
-        {
-          contentIndex: 0,
-          startIndex: 14,
-          endIndex: 31,
-        },
-        {
-          contentIndex: 2,
-          startIndex: 8,
-          endIndex: 78,
-        },
-        {
-          contentIndex: 3,
-          startIndex: 11,
-          endIndex: 78,
-        },
-        {
-          contentIndex: 4,
-          startIndex: 11,
-          endIndex: 78,
-        },
-        {
-          contentIndex: 5,
-          startIndex: 12,
-          endIndex: 41,
-        },
-      ]);
-
-      content = ['🙈 a', '🙉 b', '🙊 c'];
-      highlights = [[2, 7]];
-      results = element.convertIntralineInfos(content, highlights);
-      assert.deepEqual(results, [
-        {
-          contentIndex: 0,
-          startIndex: 2,
-        },
-        {
-          contentIndex: 1,
-          startIndex: 0,
-        },
-        {
-          contentIndex: 2,
-          startIndex: 0,
-          endIndex: 1,
-        },
-      ]);
-    });
-
-    test('isScrolling paused', () => {
-      const content = Array(200).fill({ab: ['', '']});
-      element.isScrolling = true;
-      element.process(content, false);
-      // Just the FILE and LOST groups.
-      assert.equal(groups.length, 2);
-    });
-
-    test('isScrolling unpaused', () => {
-      const content = Array(200).fill({ab: ['', '']});
-      element.isScrolling = false;
-      element.process(content, false);
-      // More groups have been processed. How many does not matter here.
-      assert.isAtLeast(groups.length, 3);
-    });
-
-    test('image diffs', () => {
-      const content = Array(200).fill({ab: ['', '']});
-      element.process(content, true);
-      assert.equal(groups.length, 2);
-
-      // Image diffs don't process content, just the 'FILE' line.
-      assert.equal(groups[0].lines.length, 1);
-    });
-
-    suite('processNext', () => {
-      let rows: string[];
-
-      setup(() => {
-        rows = loremIpsum.split(' ');
-      });
-
-      test('WHOLE_FILE', () => {
-        element.context = WHOLE_FILE;
-        const state: State = {
-          lineNums: {left: 10, right: 100},
-          chunkIndex: 1,
-        };
-        const chunks = [{a: ['foo']}, {ab: rows}, {a: ['bar']}];
-        const result = element.processNext(state, chunks);
-
-        // Results in one, uncollapsed group with all rows.
-        assert.equal(result.groups.length, 1);
-        assert.equal(result.groups[0].type, GrDiffGroupType.BOTH);
-        assert.equal(result.groups[0].lines.length, rows.length);
-
-        // Line numbers are set correctly.
-        assert.equal(
-          result.groups[0].lines[0].beforeNumber,
-          state.lineNums.left + 1
-        );
-        assert.equal(
-          result.groups[0].lines[0].afterNumber,
-          state.lineNums.right + 1
-        );
-
-        assert.equal(
-          result.groups[0].lines[rows.length - 1].beforeNumber,
-          state.lineNums.left + rows.length
-        );
-        assert.equal(
-          result.groups[0].lines[rows.length - 1].afterNumber,
-          state.lineNums.right + rows.length
-        );
-      });
-
-      test('WHOLE_FILE with skip chunks still get collapsed', () => {
-        element.context = WHOLE_FILE;
-        const lineNums = {left: 10, right: 100};
-        const state = {
-          lineNums,
-          chunkIndex: 1,
-        };
-        const skip = 10000;
-        const chunks = [{a: ['foo']}, {skip}, {ab: rows}, {a: ['bar']}];
-        const result = element.processNext(state, chunks);
-        // Results in one, uncollapsed group with all rows.
-        assert.equal(result.groups.length, 1);
-        assert.equal(result.groups[0].type, GrDiffGroupType.CONTEXT_CONTROL);
-
-        // Skip and ab group are hidden in the same context control
-        assert.equal(result.groups[0].contextGroups.length, 2);
-        const [skippedGroup, abGroup] = result.groups[0].contextGroups;
-
-        // Line numbers are set correctly.
-        assert.deepEqual(skippedGroup.lineRange, {
-          left: {
-            start_line: lineNums.left + 1,
-            end_line: lineNums.left + skip,
-          },
-          right: {
-            start_line: lineNums.right + 1,
-            end_line: lineNums.right + skip,
-          },
-        });
-
-        assert.deepEqual(abGroup.lineRange, {
-          left: {
-            start_line: lineNums.left + skip + 1,
-            end_line: lineNums.left + skip + rows.length,
-          },
-          right: {
-            start_line: lineNums.right + skip + 1,
-            end_line: lineNums.right + skip + rows.length,
-          },
-        });
-      });
-
-      test('with context', () => {
-        element.context = 10;
-        const state = {
-          lineNums: {left: 10, right: 100},
-          chunkIndex: 1,
-        };
-        const chunks = [{a: ['foo']}, {ab: rows}, {a: ['bar']}];
-        const result = element.processNext(state, chunks);
-        const expectedCollapseSize = rows.length - 2 * element.context;
-
-        assert.equal(result.groups.length, 3, 'Results in three groups');
-
-        // The first and last are uncollapsed context, whereas the middle has
-        // a single context-control line.
-        assert.equal(result.groups[0].lines.length, element.context);
-        assert.equal(result.groups[2].lines.length, element.context);
-
-        // The collapsed group has the hidden lines as its context group.
-        assert.equal(
-          result.groups[1].contextGroups[0].lines.length,
-          expectedCollapseSize
-        );
-      });
-
-      test('first', () => {
-        element.context = 10;
-        const state = {
-          lineNums: {left: 10, right: 100},
-          chunkIndex: 0,
-        };
-        const chunks = [{ab: rows}, {a: ['foo']}, {a: ['bar']}];
-        const result = element.processNext(state, chunks);
-        const expectedCollapseSize = rows.length - element.context;
-
-        assert.equal(result.groups.length, 2, 'Results in two groups');
-
-        // Only the first group is collapsed.
-        assert.equal(result.groups[1].lines.length, element.context);
-
-        // The collapsed group has the hidden lines as its context group.
-        assert.equal(
-          result.groups[0].contextGroups[0].lines.length,
-          expectedCollapseSize
-        );
-      });
-
-      test('few-rows', () => {
-        // Only ten rows.
-        rows = rows.slice(0, 10);
-        element.context = 10;
-        const state = {
-          lineNums: {left: 10, right: 100},
-          chunkIndex: 0,
-        };
-        const chunks = [{ab: rows}, {a: ['foo']}, {a: ['bar']}];
-        const result = element.processNext(state, chunks);
-
-        // Results in one uncollapsed group with all rows.
-        assert.equal(result.groups.length, 1, 'Results in one group');
-        assert.equal(result.groups[0].lines.length, rows.length);
-      });
-
-      test('no single line collapse', () => {
-        rows = rows.slice(0, 7);
-        element.context = 3;
-        const state = {
-          lineNums: {left: 10, right: 100},
-          chunkIndex: 1,
-        };
-        const chunks = [{a: ['foo']}, {ab: rows}, {a: ['bar']}];
-        const result = element.processNext(state, chunks);
-
-        // Results in one uncollapsed group with all rows.
-        assert.equal(result.groups.length, 1, 'Results in one group');
-        assert.equal(result.groups[0].lines.length, rows.length);
-      });
-
-      suite('with key location', () => {
-        let state: State;
-        let chunks: DiffContent[];
-
-        setup(() => {
-          state = {
-            lineNums: {left: 10, right: 100},
-            chunkIndex: 0,
-          };
-          element.context = 10;
-          chunks = [{ab: rows}, {ab: ['foo'], keyLocation: true}, {ab: rows}];
-        });
-
-        test('context before', () => {
-          state.chunkIndex = 0;
-          const result = element.processNext(state, chunks);
-
-          // The first chunk is split into two groups:
-          // 1) A context-control, hiding everything but the context before
-          //    the key location.
-          // 2) The context before the key location.
-          // The key location is not processed in this call to processNext
-          assert.equal(result.groups.length, 2);
-          // The collapsed group has the hidden lines as its context group.
-          assert.equal(
-            result.groups[0].contextGroups[0].lines.length,
-            rows.length - element.context
-          );
-          assert.equal(result.groups[1].lines.length, element.context);
-        });
-
-        test('key location itself', () => {
-          state.chunkIndex = 1;
-          const result = element.processNext(state, chunks);
-
-          // The second chunk results in a single group, that is just the
-          // line with the key location
-          assert.equal(result.groups.length, 1);
-          assert.equal(result.groups[0].lines.length, 1);
-          assert.equal(result.lineDelta.left, 1);
-          assert.equal(result.lineDelta.right, 1);
-        });
-
-        test('context after', () => {
-          state.chunkIndex = 2;
-          const result = element.processNext(state, chunks);
-
-          // The last chunk is split into two groups:
-          // 1) The context after the key location.
-          // 1) A context-control, hiding everything but the context after the
-          //    key location.
-          assert.equal(result.groups.length, 2);
-          assert.equal(result.groups[0].lines.length, element.context);
-          // The collapsed group has the hidden lines as its context group.
-          assert.equal(
-            result.groups[1].contextGroups[0].lines.length,
-            rows.length - element.context
-          );
-        });
-      });
-    });
-
-    suite('gr-diff-processor helpers', () => {
-      let rows: string[];
-
-      setup(() => {
-        rows = loremIpsum.split(' ');
-      });
-
-      test('linesFromRows', () => {
-        const startLineNum = 10;
-        let result = element.linesFromRows(
-          GrDiffLineType.ADD,
-          rows,
-          startLineNum + 1
-        );
-
-        assert.equal(result.length, rows.length);
-        assert.equal(result[0].type, GrDiffLineType.ADD);
-        assert.notOk(result[0].hasIntralineInfo);
-        assert.equal(result[0].afterNumber, startLineNum + 1);
-        assert.notOk(result[0].beforeNumber);
-        assert.equal(
-          result[result.length - 1].afterNumber,
-          startLineNum + rows.length
-        );
-        assert.notOk(result[result.length - 1].beforeNumber);
-
-        result = element.linesFromRows(
-          GrDiffLineType.REMOVE,
-          rows,
-          startLineNum + 1
-        );
-
-        assert.equal(result.length, rows.length);
-        assert.equal(result[0].type, GrDiffLineType.REMOVE);
-        assert.notOk(result[0].hasIntralineInfo);
-        assert.equal(result[0].beforeNumber, startLineNum + 1);
-        assert.notOk(result[0].afterNumber);
-        assert.equal(
-          result[result.length - 1].beforeNumber,
-          startLineNum + rows.length
-        );
-        assert.notOk(result[result.length - 1].afterNumber);
-      });
-    });
-
-    suite('breakdown*', () => {
-      test('breakdownChunk breaks down additions', () => {
-        const breakdownSpy = sinon.spy(element, 'breakdown');
-        const chunk = {b: ['blah', 'blah', 'blah']};
-        const result = element.breakdownChunk(chunk);
-        assert.deepEqual(result, [chunk]);
-        assert.isTrue(breakdownSpy.called);
-      });
-
-      test('breakdownChunk keeps due_to_rebase for broken down additions', () => {
-        sinon.spy(element, 'breakdown');
-        const chunk = {b: ['blah', 'blah', 'blah'], due_to_rebase: true};
-        const result = element.breakdownChunk(chunk);
-        for (const subResult of result) {
-          assert.isTrue(subResult.due_to_rebase);
-        }
-      });
-
-      test('breakdown common case', () => {
-        const array = 'Lorem ipsum dolor sit amet, suspendisse inceptos'.split(
-          ' '
-        );
-        const size = 3;
-
-        const result = element.breakdown(array, size);
-
-        for (const subResult of result) {
-          assert.isAtMost(subResult.length, size);
-        }
-        const flattened = result.reduce((a, b) => a.concat(b), []);
-        assert.deepEqual(flattened, array);
-      });
-
-      test('breakdown smaller than size', () => {
-        const array = 'Lorem ipsum dolor sit amet, suspendisse inceptos'.split(
-          ' '
-        );
-        const size = 10;
-        const expected = [array];
-
-        const result = element.breakdown(array, size);
-
-        assert.deepEqual(result, expected);
-      });
-
-      test('breakdown empty', () => {
-        const array: string[] = [];
-        const size = 10;
-        const expected: string[][] = [];
-
-        const result = element.breakdown(array, size);
-
-        assert.deepEqual(result, expected);
-      });
-    });
-  });
-});
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff-selection/gr-diff-selection.ts b/polygerrit-ui/app/embed/diff-old/gr-diff-selection/gr-diff-selection.ts
deleted file mode 100644
index 407b403..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff-selection/gr-diff-selection.ts
+++ /dev/null
@@ -1,189 +0,0 @@
-/**
- * @license
- * Copyright 2016 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import '../../../styles/shared-styles';
-import {normalize} from '../gr-diff-highlight/gr-range-normalizer';
-import {
-  descendedFromClass,
-  parentWithClass,
-  querySelectorAll,
-} from '../../../utils/dom-util';
-import {DiffInfo} from '../../../types/diff';
-import {Side} from '../../../constants/constants';
-import {
-  getLineElByChild,
-  getSide,
-  getSideByLineEl,
-  isThreadEl,
-} from '../../diff/gr-diff/gr-diff-utils';
-import {getContentFromDiff} from '../../../utils/diff-util';
-
-/**
- * Possible CSS classes indicating the state of selection. Dynamically added/
- * removed based on where the user clicks within the diff.
- */
-const SelectionClass = {
-  COMMENT: 'selected-comment',
-  LEFT: 'selected-left',
-  RIGHT: 'selected-right',
-  BLAME: 'selected-blame',
-};
-
-function selectionClassForSide(side?: Side) {
-  return side === Side.LEFT ? SelectionClass.LEFT : SelectionClass.RIGHT;
-}
-
-export class GrDiffSelection {
-  // visible for testing
-  diff?: DiffInfo;
-
-  // visible for testing
-  diffTable?: HTMLElement;
-
-  init(diff: DiffInfo, diffTable: HTMLElement) {
-    this.cleanup();
-    this.diff = diff;
-    this.diffTable = diffTable;
-    this.diffTable.classList.add(SelectionClass.RIGHT);
-    this.diffTable.addEventListener('copy', this.handleCopy);
-    this.diffTable.addEventListener('mousedown', this.handleDown);
-  }
-
-  cleanup() {
-    if (!this.diffTable) return;
-    this.diffTable.removeEventListener('copy', this.handleCopy);
-    this.diffTable.removeEventListener('mousedown', this.handleDown);
-  }
-
-  handleDown = (e: Event) => {
-    const target = e.target;
-    if (!(target instanceof Element)) return;
-
-    const commentEl = parentWithClass(target, 'comment-thread', this.diffTable);
-    if (commentEl && isThreadEl(commentEl)) {
-      this.setClasses([
-        SelectionClass.COMMENT,
-        selectionClassForSide(getSide(commentEl)),
-      ]);
-      return;
-    }
-
-    const blameSelected = descendedFromClass(target, 'blame', this.diffTable);
-    if (blameSelected) {
-      this.setClasses([SelectionClass.BLAME]);
-      return;
-    }
-
-    // This works for both, the content and the line number cells.
-    const lineEl = getLineElByChild(target);
-    if (lineEl) {
-      this.setClasses([selectionClassForSide(getSideByLineEl(lineEl))]);
-      return;
-    }
-  };
-
-  /**
-   * Set the provided list of classes on the element, to the exclusion of all
-   * other SelectionClass values.
-   */
-  setClasses(targetClasses: string[]) {
-    if (!this.diffTable) return;
-    // Remove any selection classes that do not belong.
-    for (const className of Object.values(SelectionClass)) {
-      if (!targetClasses.includes(className)) {
-        this.diffTable.classList.remove(className);
-      }
-    }
-    // Add new selection classes iff they are not already present.
-    for (const targetClass of targetClasses) {
-      if (!this.diffTable.classList.contains(targetClass)) {
-        this.diffTable.classList.add(targetClass);
-      }
-    }
-  }
-
-  handleCopy = (e: ClipboardEvent) => {
-    const target = e.composedPath()[0];
-    if (!(target instanceof Element)) return;
-    if (target instanceof HTMLTextAreaElement) return;
-    if (!descendedFromClass(target, 'diff-row', this.diffTable)) return;
-    if (!this.diffTable) return;
-    if (this.diffTable.classList.contains(SelectionClass.COMMENT)) return;
-
-    const lineEl = getLineElByChild(target);
-    if (!lineEl) return;
-    const side = getSideByLineEl(lineEl);
-    const text = this.getSelectedText(side);
-    if (text && e.clipboardData) {
-      e.clipboardData.setData('Text', text);
-      e.preventDefault();
-    }
-  };
-
-  getSelection() {
-    const diffHosts = querySelectorAll(document.body, 'gr-diff');
-    if (!diffHosts.length) return document.getSelection();
-
-    const curDiffHost = diffHosts.find(diffHost => {
-      if (!diffHost?.shadowRoot?.getSelection) return false;
-      const selection = diffHost.shadowRoot.getSelection();
-      // Pick the one with valid selection:
-      // https://developer.mozilla.org/en-US/docs/Web/API/Selection/type
-      return selection && selection.type !== 'None';
-    });
-
-    return curDiffHost?.shadowRoot?.getSelection
-      ? curDiffHost.shadowRoot.getSelection()
-      : document.getSelection();
-  }
-
-  /**
-   * Get the text of the current selection. If commentSelected is
-   * true, it returns only the text of comments within the selection.
-   * Otherwise it returns the text of the selected diff region.
-   *
-   * @param side The side that is selected.
-   * @param commentSelected Whether or not a comment is selected.
-   * @return The selected text.
-   */
-  getSelectedText(side: Side) {
-    if (!this.diff) return '';
-    const sel = this.getSelection();
-    if (!sel || sel.rangeCount !== 1) {
-      return ''; // No multi-select support yet.
-    }
-    const range = normalize(sel.getRangeAt(0));
-    const startLineEl = getLineElByChild(range.startContainer);
-    if (!startLineEl) return;
-    const endLineEl = getLineElByChild(range.endContainer);
-    // Happens when triple click in side-by-side mode with other side empty.
-    const endsAtOtherEmptySide =
-      !endLineEl &&
-      range.endOffset === 0 &&
-      range.endContainer.nodeName === 'TD' &&
-      range.endContainer instanceof HTMLTableCellElement &&
-      (range.endContainer.classList.contains('left') ||
-        range.endContainer.classList.contains('right'));
-    const startLineDataValue = startLineEl.getAttribute('data-value');
-    if (!startLineDataValue) return;
-    const startLineNum = Number(startLineDataValue);
-    let endLineNum;
-    if (endsAtOtherEmptySide) {
-      endLineNum = startLineNum + 1;
-    } else if (endLineEl) {
-      const endLineDataValue = endLineEl.getAttribute('data-value');
-      if (endLineDataValue) endLineNum = Number(endLineDataValue);
-    }
-
-    return getContentFromDiff(
-      this.diff,
-      startLineNum,
-      range.startOffset,
-      endLineNum,
-      range.endOffset,
-      side
-    );
-  }
-}
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff-selection/gr-diff-selection_test.ts b/polygerrit-ui/app/embed/diff-old/gr-diff-selection/gr-diff-selection_test.ts
deleted file mode 100644
index f216e04..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff-selection/gr-diff-selection_test.ts
+++ /dev/null
@@ -1,219 +0,0 @@
-/**
- * @license
- * Copyright 2016 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import '../../../test/common-test-setup';
-import './gr-diff-selection';
-import '../gr-diff/gr-diff';
-import '../../../elements/shared/gr-comment-thread/gr-comment-thread';
-import {GrDiffSelection} from './gr-diff-selection';
-import {createDiff} from '../../../test/test-data-generators';
-import {DiffInfo, Side} from '../../../api/diff';
-import {fixture, html, assert} from '@open-wc/testing';
-import {mouseDown} from '../../../test/test-utils';
-import {GrDiff} from '../gr-diff/gr-diff';
-import {waitForEventOnce} from '../../../utils/event-util';
-import {createDefaultDiffPrefs} from '../../../constants/constants';
-
-function firstTextNode(el: HTMLElement) {
-  return [...el.childNodes].filter(node => node.nodeType === Node.TEXT_NODE)[0];
-}
-
-suite('gr-diff-selection', () => {
-  let element: GrDiffSelection;
-  let diffTable: HTMLElement;
-  let grDiff: GrDiff;
-
-  const emulateCopyOn = function (target: HTMLElement | null) {
-    const fakeEvent = {
-      target,
-      preventDefault: sinon.stub(),
-      composedPath() {
-        return [target];
-      },
-      clipboardData: {
-        setData: sinon.stub(),
-      },
-    };
-    element.handleCopy(fakeEvent as unknown as ClipboardEvent);
-    return fakeEvent;
-  };
-
-  setup(async () => {
-    grDiff = await fixture<GrDiff>(html`<gr-diff></gr-diff>`);
-    element = grDiff.diffSelection;
-
-    const diff: DiffInfo = {
-      ...createDiff(),
-      content: [
-        {
-          a: ['ba ba'],
-          b: ['some other text'],
-        },
-        {
-          a: ['zin'],
-          b: ['more more more'],
-        },
-        {
-          a: ['ga ga'],
-          b: ['some other text'],
-        },
-      ],
-    };
-    grDiff.prefs = createDefaultDiffPrefs();
-    grDiff.diff = diff;
-    await waitForEventOnce(grDiff, 'render');
-    assert.isOk(element.diffTable);
-    diffTable = element.diffTable!;
-  });
-
-  test('applies selected-left on left side click', () => {
-    diffTable.classList.add('selected-right');
-    const lineNumberEl = diffTable.querySelector<HTMLElement>('.lineNum.left');
-    if (!lineNumberEl) assert.fail('line number element missing');
-    mouseDown(lineNumberEl);
-    assert.isTrue(
-      diffTable.classList.contains('selected-left'),
-      'adds selected-left'
-    );
-    assert.isFalse(
-      diffTable.classList.contains('selected-right'),
-      'removes selected-right'
-    );
-  });
-
-  test('applies selected-right on right side click', () => {
-    diffTable.classList.add('selected-left');
-    const lineNumberEl = diffTable.querySelector<HTMLElement>('.lineNum.right');
-    if (!lineNumberEl) assert.fail('line number element missing');
-    mouseDown(lineNumberEl);
-    assert.isTrue(
-      diffTable.classList.contains('selected-right'),
-      'adds selected-right'
-    );
-    assert.isFalse(
-      diffTable.classList.contains('selected-left'),
-      'removes selected-left'
-    );
-  });
-
-  test('applies selected-blame on blame click', () => {
-    diffTable.classList.add('selected-left');
-    const blameDiv = document.createElement('div');
-    blameDiv.classList.add('blame');
-    diffTable.appendChild(blameDiv);
-    mouseDown(blameDiv);
-    assert.isTrue(
-      diffTable.classList.contains('selected-blame'),
-      'adds selected-right'
-    );
-    assert.isFalse(
-      diffTable.classList.contains('selected-left'),
-      'removes selected-left'
-    );
-  });
-
-  test('ignores copy for non-content Element', () => {
-    const getSelectedTextStub = sinon.stub(element, 'getSelectedText');
-    emulateCopyOn(diffTable.querySelector('.not-diff-row'));
-    assert.isFalse(getSelectedTextStub.called);
-  });
-
-  test('asks for text for left side Elements', () => {
-    const getSelectedTextStub = sinon.stub(element, 'getSelectedText');
-    emulateCopyOn(diffTable.querySelector('div.contentText'));
-    assert.deepEqual([Side.LEFT], getSelectedTextStub.lastCall.args);
-  });
-
-  test('reacts to copy for content Elements', () => {
-    const getSelectedTextStub = sinon.stub(element, 'getSelectedText');
-    emulateCopyOn(diffTable.querySelector('div.contentText'));
-    assert.isTrue(getSelectedTextStub.called);
-  });
-
-  test('copy event is prevented for content Elements', () => {
-    const getSelectedTextStub = sinon.stub(element, 'getSelectedText');
-    getSelectedTextStub.returns('test');
-    const event = emulateCopyOn(diffTable.querySelector('div.contentText'));
-    assert.isTrue(event.preventDefault.called);
-  });
-
-  test('inserts text into clipboard on copy', () => {
-    sinon.stub(element, 'getSelectedText').returns('the text');
-    const event = emulateCopyOn(diffTable.querySelector('div.contentText'));
-    assert.deepEqual(
-      ['Text', 'the text'],
-      event.clipboardData.setData.lastCall.args
-    );
-  });
-
-  test('setClasses adds given SelectionClass values, removes others', () => {
-    diffTable.classList.add('selected-right');
-    element.setClasses(['selected-comment', 'selected-left']);
-    assert.isTrue(diffTable.classList.contains('selected-comment'));
-    assert.isTrue(diffTable.classList.contains('selected-left'));
-    assert.isFalse(diffTable.classList.contains('selected-right'));
-    assert.isFalse(diffTable.classList.contains('selected-blame'));
-
-    element.setClasses(['selected-blame']);
-    assert.isFalse(diffTable.classList.contains('selected-comment'));
-    assert.isFalse(diffTable.classList.contains('selected-left'));
-    assert.isFalse(diffTable.classList.contains('selected-right'));
-    assert.isTrue(diffTable.classList.contains('selected-blame'));
-  });
-
-  test('setClasses removes before it ads', () => {
-    diffTable.classList.add('selected-right');
-    const addStub = sinon.stub(diffTable.classList, 'add');
-    const removeStub = sinon
-      .stub(diffTable.classList, 'remove')
-      .callsFake(() => {
-        assert.isFalse(addStub.called);
-      });
-    element.setClasses(['selected-comment', 'selected-left']);
-    assert.isTrue(addStub.called);
-    assert.isTrue(removeStub.called);
-  });
-
-  test('copies content correctly', () => {
-    diffTable.classList.add('selected-left');
-    diffTable.classList.remove('selected-right');
-
-    const selection = document.getSelection();
-    if (selection === null) assert.fail('no selection');
-    selection.removeAllRanges();
-    const range = document.createRange();
-    const texts = diffTable.querySelectorAll<HTMLElement>('gr-diff-text');
-    range.setStart(firstTextNode(texts[0]), 3);
-    range.setEnd(firstTextNode(texts[4]), 2);
-    selection.addRange(range);
-
-    assert.equal(element.getSelectedText(Side.LEFT), 'ba\nzin\nga');
-  });
-
-  test('defers to default behavior for textarea', () => {
-    diffTable.classList.add('selected-left');
-    diffTable.classList.remove('selected-right');
-    const selectedTextSpy = sinon.spy(element, 'getSelectedText');
-    emulateCopyOn(diffTable.querySelector('textarea'));
-
-    assert.isFalse(selectedTextSpy.called);
-  });
-
-  test('regression test for 4794', () => {
-    diffTable.classList.add('selected-right');
-    diffTable.classList.remove('selected-left');
-
-    const selection = document.getSelection();
-    if (!selection) assert.fail('no selection');
-    selection.removeAllRanges();
-    const range = document.createRange();
-    const texts = diffTable.querySelectorAll<HTMLElement>('gr-diff-text');
-    range.setStart(firstTextNode(texts[1]), 4);
-    range.setEnd(firstTextNode(texts[1]), 10);
-    selection.addRange(range);
-
-    assert.equal(element.getSelectedText(Side.RIGHT), ' other');
-  });
-});
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff-group.ts b/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff-group.ts
deleted file mode 100644
index 771e298..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff-group.ts
+++ /dev/null
@@ -1,520 +0,0 @@
-/**
- * @license
- * Copyright 2016 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import {BLANK_LINE, GrDiffLine} from './gr-diff-line';
-import {GrDiffLineType, LineNumber, LineRange, Side} from '../../../api/diff';
-import {assertIsDefined, assert} from '../../../utils/common-util';
-import {untilRendered} from '../../../utils/dom-util';
-import {isDefined} from '../../../types/types';
-import {LitElement} from 'lit';
-
-export enum GrDiffGroupType {
-  /** Unchanged context. */
-  BOTH = 'both',
-
-  /** A widget used to show more context. */
-  CONTEXT_CONTROL = 'contextControl',
-
-  /** Added, removed or modified chunk. */
-  DELTA = 'delta',
-}
-
-export interface GrDiffLinePair {
-  left: GrDiffLine;
-  right: GrDiffLine;
-}
-
-/**
- * Hides lines in the given range behind a context control group.
- *
- * Groups that would be partially visible are split into their visible and
- * hidden parts, respectively.
- * The groups need to be "common groups", meaning they have to have either
- * originated from an `ab` chunk, or from an `a`+`b` chunk with
- * `common: true`.
- *
- * If the hidden range is 3 lines or less, nothing is hidden and no context
- * control group is created.
- *
- * @param groups Common groups, ordered by their line ranges.
- * @param hiddenStart The first element to be hidden, as a
- *     non-negative line number offset relative to the first group's start
- *     line, left and right respectively.
- * @param hiddenEnd The first visible element after the hidden range,
- *     as a non-negative line number offset relative to the first group's
- *     start line, left and right respectively.
- */
-export function hideInContextControl(
-  groups: readonly GrDiffGroup[],
-  hiddenStart: number,
-  hiddenEnd: number
-): GrDiffGroup[] {
-  if (groups.length === 0) return [];
-  // Clamp hiddenStart and hiddenEnd - inspired by e.g. substring
-  hiddenStart = Math.max(hiddenStart, 0);
-  hiddenEnd = Math.max(hiddenEnd, hiddenStart);
-
-  let before: GrDiffGroup[] = [];
-  let hidden = groups;
-  let after: readonly GrDiffGroup[] = [];
-
-  const numHidden = hiddenEnd - hiddenStart;
-
-  // Showing a context control row for less than 4 lines does not make much,
-  // because then that row would consume as much space as the collapsed code.
-  if (numHidden > 3) {
-    if (hiddenStart) {
-      [before, hidden] = splitCommonGroups(hidden, hiddenStart);
-    }
-    if (hiddenEnd) {
-      let beforeLength = 0;
-      if (before.length > 0) {
-        const beforeStart = before[0].lineRange.left.start_line;
-        const beforeEnd = before[before.length - 1].lineRange.left.end_line;
-        beforeLength = beforeEnd - beforeStart + 1;
-      }
-      [hidden, after] = splitCommonGroups(hidden, hiddenEnd - beforeLength);
-    }
-  } else {
-    [hidden, after] = [[], hidden];
-  }
-
-  const result = [...before];
-  if (hidden.length) {
-    result.push(
-      new GrDiffGroup({
-        type: GrDiffGroupType.CONTEXT_CONTROL,
-        contextGroups: [...hidden],
-      })
-    );
-  }
-  result.push(...after);
-  return result;
-}
-
-/**
- * Splits a group in two, defined by leftSplit and rightSplit. Primarily to be
- * used in function splitCommonGroups
- * Groups with some lines before and some lines after the split will be split
- * into two groups, which will be put into the first and second list.
- *
- * @param group The group to be split in two
- * @param leftSplit The line number relative to the split on the left side
- * @param rightSplit The line number relative to the split on the right side
- * @return two new groups, one before the split and another after it
- */
-function splitGroupInTwo(
-  group: GrDiffGroup,
-  leftSplit: number,
-  rightSplit: number
-) {
-  let beforeSplit: GrDiffGroup | undefined;
-  let afterSplit: GrDiffGroup | undefined;
-  // split line is in the middle of a group, we need to break the group
-  // in lines before and after the split.
-  if (group.skip) {
-    // Currently we assume skip chunks "refuse" to be split. Expanding this
-    // group will in the future mean load more data - and therefore we want to
-    // fire an event when user wants to do it.
-    const closerToStartThanEnd =
-      leftSplit - group.lineRange.left.start_line <
-      group.lineRange.right.end_line - leftSplit;
-    if (closerToStartThanEnd) {
-      afterSplit = group;
-    } else {
-      beforeSplit = group;
-    }
-  } else {
-    const before = [];
-    const after = [];
-    for (const line of group.lines) {
-      if (
-        (line.beforeNumber &&
-          typeof line.beforeNumber === 'number' &&
-          line.beforeNumber < leftSplit) ||
-        (line.afterNumber &&
-          typeof line.afterNumber === 'number' &&
-          line.afterNumber < rightSplit)
-      ) {
-        before.push(line);
-      } else {
-        after.push(line);
-      }
-    }
-    if (before.length) {
-      beforeSplit =
-        before.length === group.lines.length
-          ? group
-          : group.cloneWithLines(before);
-    }
-    if (after.length) {
-      afterSplit =
-        after.length === group.lines.length
-          ? group
-          : group.cloneWithLines(after);
-    }
-  }
-  return {beforeSplit, afterSplit};
-}
-
-/**
- * Splits a list of common groups into two lists of groups.
- *
- * Groups where all lines are before or all lines are after the split will be
- * retained as is and put into the first or second list respectively. Groups
- * with some lines before and some lines after the split will be split into
- * two groups, which will be put into the first and second list.
- *
- * @param split A line number offset relative to the first group's
- *     start line at which the groups should be split.
- * @return The outer array has 2 elements, the
- *   list of groups before and the list of groups after the split.
- */
-function splitCommonGroups(
-  groups: readonly GrDiffGroup[],
-  split: number
-): GrDiffGroup[][] {
-  if (groups.length === 0) return [[], []];
-  const leftSplit = groups[0].lineRange.left.start_line + split;
-  const rightSplit = groups[0].lineRange.right.start_line + split;
-
-  const beforeGroups = [];
-  const afterGroups = [];
-  for (const group of groups) {
-    const isCompletelyBefore =
-      group.lineRange.left.end_line < leftSplit ||
-      group.lineRange.right.end_line < rightSplit;
-    const isCompletelyAfter =
-      leftSplit <= group.lineRange.left.start_line ||
-      rightSplit <= group.lineRange.right.start_line;
-    if (isCompletelyBefore) {
-      beforeGroups.push(group);
-    } else if (isCompletelyAfter) {
-      afterGroups.push(group);
-    } else {
-      const {beforeSplit, afterSplit} = splitGroupInTwo(
-        group,
-        leftSplit,
-        rightSplit
-      );
-      if (beforeSplit) {
-        beforeGroups.push(beforeSplit);
-      }
-      if (afterSplit) {
-        afterGroups.push(afterSplit);
-      }
-    }
-  }
-  return [beforeGroups, afterGroups];
-}
-
-export interface GrMoveDetails {
-  changed: boolean;
-  range?: {
-    start: number;
-    end: number;
-  };
-}
-
-/** A chunk of the diff that should be rendered together. */
-export class GrDiffGroup {
-  constructor(
-    options:
-      | {
-          type: GrDiffGroupType.BOTH | GrDiffGroupType.DELTA;
-          lines?: GrDiffLine[];
-          skip?: undefined;
-          moveDetails?: GrMoveDetails;
-          dueToRebase?: boolean;
-          ignoredWhitespaceOnly?: boolean;
-          keyLocation?: boolean;
-        }
-      | {
-          type: GrDiffGroupType.BOTH | GrDiffGroupType.DELTA;
-          lines?: undefined;
-          skip: number;
-          offsetLeft: number;
-          offsetRight: number;
-          moveDetails?: GrMoveDetails;
-          dueToRebase?: boolean;
-          ignoredWhitespaceOnly?: boolean;
-          keyLocation?: boolean;
-        }
-      | {
-          type: GrDiffGroupType.CONTEXT_CONTROL;
-          contextGroups: GrDiffGroup[];
-        }
-  ) {
-    this.type = options.type;
-    switch (options.type) {
-      case GrDiffGroupType.BOTH:
-      case GrDiffGroupType.DELTA: {
-        this.moveDetails = options.moveDetails;
-        this.dueToRebase = options.dueToRebase ?? false;
-        this.ignoredWhitespaceOnly = options.ignoredWhitespaceOnly ?? false;
-        this.keyLocation = options.keyLocation ?? false;
-        if (options.skip && options.lines) {
-          throw new Error('Cannot set skip and lines');
-        }
-        this.skip = options.skip;
-        if (options.skip !== undefined) {
-          this.lineRange = {
-            left: {
-              start_line: options.offsetLeft,
-              end_line: options.offsetLeft + options.skip - 1,
-            },
-            right: {
-              start_line: options.offsetRight,
-              end_line: options.offsetRight + options.skip - 1,
-            },
-          };
-        } else {
-          assertIsDefined(options.lines);
-          assert(options.lines.length > 0, 'diff group must have lines');
-          for (const line of options.lines) {
-            this.addLine(line);
-          }
-        }
-        break;
-      }
-      case GrDiffGroupType.CONTEXT_CONTROL: {
-        this.contextGroups = options.contextGroups;
-        if (this.contextGroups.length > 0) {
-          const firstGroup = this.contextGroups[0];
-          const lastGroup = this.contextGroups[this.contextGroups.length - 1];
-          this.lineRange = {
-            left: {
-              start_line: firstGroup.lineRange.left.start_line,
-              end_line: lastGroup.lineRange.left.end_line,
-            },
-            right: {
-              start_line: firstGroup.lineRange.right.start_line,
-              end_line: lastGroup.lineRange.right.end_line,
-            },
-          };
-        }
-        break;
-      }
-      default:
-        throw new Error(`Unknown group type: ${this.type}`);
-    }
-  }
-
-  readonly type: GrDiffGroupType;
-
-  readonly dueToRebase: boolean = false;
-
-  /**
-   * True means all changes in this line are whitespace changes that should
-   * not be highlighted as changed as per the user settings.
-   */
-  readonly ignoredWhitespaceOnly: boolean = false;
-
-  /**
-   * True means it should not be collapsed (because it was in the URL, or
-   * there is a comment on that line)
-   */
-  readonly keyLocation: boolean = false;
-
-  /**
-   * Once rendered the diff builder sets this to the diff section element.
-   */
-  element?: HTMLElement;
-
-  readonly lines: GrDiffLine[] = [];
-
-  readonly adds: GrDiffLine[] = [];
-
-  readonly removes: GrDiffLine[] = [];
-
-  readonly contextGroups: GrDiffGroup[] = [];
-
-  readonly skip?: number;
-
-  /** Both start and end line are inclusive. */
-  readonly lineRange: {[side in Side]: LineRange} = {
-    [Side.LEFT]: {start_line: 0, end_line: 0},
-    [Side.RIGHT]: {start_line: 0, end_line: 0},
-  };
-
-  readonly moveDetails?: GrMoveDetails;
-
-  /**
-   * Creates a new group with the same properties but different lines.
-   *
-   * The element property is not copied, because the original element is still a
-   * rendering of the old lines, so that would not make sense.
-   */
-  cloneWithLines(lines: GrDiffLine[]): GrDiffGroup {
-    if (
-      this.type !== GrDiffGroupType.BOTH &&
-      this.type !== GrDiffGroupType.DELTA
-    ) {
-      throw new Error('Cannot clone context group with lines');
-    }
-    const group = new GrDiffGroup({
-      type: this.type,
-      lines,
-      dueToRebase: this.dueToRebase,
-      ignoredWhitespaceOnly: this.ignoredWhitespaceOnly,
-    });
-    return group;
-  }
-
-  private addLine(line: GrDiffLine) {
-    this.lines.push(line);
-
-    const notDelta =
-      this.type === GrDiffGroupType.BOTH ||
-      this.type === GrDiffGroupType.CONTEXT_CONTROL;
-    if (
-      notDelta &&
-      (line.type === GrDiffLineType.ADD || line.type === GrDiffLineType.REMOVE)
-    ) {
-      throw Error('Cannot add delta line to a non-delta group.');
-    }
-
-    if (line.type === GrDiffLineType.ADD) {
-      this.adds.push(line);
-    } else if (line.type === GrDiffLineType.REMOVE) {
-      this.removes.push(line);
-    }
-    this._updateRangeWithNewLine(line);
-  }
-
-  getSideBySidePairs(): GrDiffLinePair[] {
-    if (
-      this.type === GrDiffGroupType.BOTH ||
-      this.type === GrDiffGroupType.CONTEXT_CONTROL
-    ) {
-      return this.lines.map(line => {
-        return {left: line, right: line};
-      });
-    }
-
-    const pairs: GrDiffLinePair[] = [];
-    let i = 0;
-    let j = 0;
-    while (i < this.removes.length || j < this.adds.length) {
-      pairs.push({
-        left: this.removes[i] || BLANK_LINE,
-        right: this.adds[j] || BLANK_LINE,
-      });
-      i++;
-      j++;
-    }
-    return pairs;
-  }
-
-  getUnifiedPairs(): GrDiffLinePair[] {
-    return this.lines
-      .map(line => {
-        if (line.type === GrDiffLineType.ADD) {
-          return {left: BLANK_LINE, right: line};
-        }
-        if (line.type === GrDiffLineType.REMOVE) {
-          if (this.ignoredWhitespaceOnly) return undefined;
-          return {left: line, right: BLANK_LINE};
-        }
-        return {left: line, right: line};
-      })
-      .filter(isDefined);
-  }
-
-  /** Returns true if it is, or contains, a skip group. */
-  hasSkipGroup() {
-    return (
-      this.skip !== undefined ||
-      this.contextGroups?.some(g => g.skip !== undefined)
-    );
-  }
-
-  containsLine(side: Side, line: LineNumber) {
-    if (typeof line !== 'number') {
-      // For FILE and LOST, beforeNumber and afterNumber are the same
-      return this.lines[0]?.beforeNumber === line;
-    }
-    const lineRange = this.lineRange[side];
-    return lineRange.start_line <= line && line <= lineRange.end_line;
-  }
-
-  startLine(side: Side): LineNumber {
-    // For both CONTEXT_CONTROL groups and SKIP groups the `lines` array will
-    // be empty. So we have to use `lineRange` instead of looking at the first
-    // line.
-    if (
-      this.type === GrDiffGroupType.CONTEXT_CONTROL ||
-      this.skip !== undefined
-    ) {
-      return side === Side.LEFT
-        ? this.lineRange.left.start_line
-        : this.lineRange.right.start_line;
-    }
-    // For "normal" groups we could also use the `lineRange`, but for FILE or
-    // LOST lines we want to return FILE or LOST. The `lineRange` contains
-    // numbers only.
-    return this.lines[0].lineNumber(side);
-  }
-
-  private _updateRangeWithNewLine(line: GrDiffLine) {
-    if (typeof line.beforeNumber !== 'number') return;
-    if (typeof line.afterNumber !== 'number') return;
-
-    if (line.type === GrDiffLineType.ADD || line.type === GrDiffLineType.BOTH) {
-      if (
-        this.lineRange.right.start_line === 0 ||
-        line.afterNumber < this.lineRange.right.start_line
-      ) {
-        this.lineRange.right.start_line = line.afterNumber;
-      }
-      if (line.afterNumber > this.lineRange.right.end_line) {
-        this.lineRange.right.end_line = line.afterNumber;
-      }
-    }
-
-    if (
-      line.type === GrDiffLineType.REMOVE ||
-      line.type === GrDiffLineType.BOTH
-    ) {
-      if (
-        this.lineRange.left.start_line === 0 ||
-        line.beforeNumber < this.lineRange.left.start_line
-      ) {
-        this.lineRange.left.start_line = line.beforeNumber;
-      }
-      if (line.beforeNumber > this.lineRange.left.end_line) {
-        this.lineRange.left.end_line = line.beforeNumber;
-      }
-    }
-  }
-
-  async waitUntilRendered() {
-    const lineNumber = this.lines[0]?.beforeNumber;
-    // The LOST or FILE lines may be hidden and thus never resolve an
-    // untilRendered() promise.
-    if (
-      this.skip !== undefined ||
-      typeof lineNumber !== 'number' ||
-      this.type === GrDiffGroupType.CONTEXT_CONTROL
-    ) {
-      return Promise.resolve();
-    }
-    assertIsDefined(this.element);
-    await (this.element as LitElement).updateComplete;
-    await untilRendered(this.element.firstElementChild as HTMLElement);
-  }
-
-  /**
-   * Determines whether the group is either totally an addition or totally
-   * a removal.
-   */
-  isTotal(): boolean {
-    return (
-      this.type === GrDiffGroupType.DELTA &&
-      (!this.adds.length || !this.removes.length) &&
-      !(!this.adds.length && !this.removes.length)
-    );
-  }
-}
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff-group_test.ts b/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff-group_test.ts
deleted file mode 100644
index bbbb4ad..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff-group_test.ts
+++ /dev/null
@@ -1,314 +0,0 @@
-/**
- * @license
- * Copyright 2016 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import '../../../test/common-test-setup';
-import {GrDiffLine, BLANK_LINE} from './gr-diff-line';
-import {
-  GrDiffGroup,
-  GrDiffGroupType,
-  hideInContextControl,
-} from './gr-diff-group';
-import {assert} from '@open-wc/testing';
-import {FILE, GrDiffLineType, LOST, Side} from '../../../api/diff';
-
-suite('gr-diff-group tests', () => {
-  test('delta line pairs', () => {
-    const l1 = new GrDiffLine(GrDiffLineType.ADD, 0, 128);
-    const l2 = new GrDiffLine(GrDiffLineType.ADD, 0, 129);
-    const l3 = new GrDiffLine(GrDiffLineType.REMOVE, 64, 0);
-    let group = new GrDiffGroup({
-      type: GrDiffGroupType.DELTA,
-      lines: [l1, l2, l3],
-    });
-    assert.deepEqual(group.lines, [l1, l2, l3]);
-    assert.deepEqual(group.adds, [l1, l2]);
-    assert.deepEqual(group.removes, [l3]);
-    assert.deepEqual(group.lineRange, {
-      left: {start_line: 64, end_line: 64},
-      right: {start_line: 128, end_line: 129},
-    });
-
-    let pairs = group.getSideBySidePairs();
-    assert.deepEqual(pairs, [
-      {left: l3, right: l1},
-      {left: BLANK_LINE, right: l2},
-    ]);
-
-    group = new GrDiffGroup({type: GrDiffGroupType.DELTA, lines: [l1, l2, l3]});
-    assert.deepEqual(group.lines, [l1, l2, l3]);
-    assert.deepEqual(group.adds, [l1, l2]);
-    assert.deepEqual(group.removes, [l3]);
-
-    pairs = group.getSideBySidePairs();
-    assert.deepEqual(pairs, [
-      {left: l3, right: l1},
-      {left: BLANK_LINE, right: l2},
-    ]);
-  });
-
-  test('group must have lines', () => {
-    try {
-      new GrDiffGroup({type: GrDiffGroupType.BOTH});
-    } catch (e) {
-      // expected
-      return;
-    }
-    assert.fail('a standard diff group cannot be empty');
-  });
-
-  test('group/header line pairs', () => {
-    const l1 = new GrDiffLine(GrDiffLineType.BOTH, 64, 128);
-    const l2 = new GrDiffLine(GrDiffLineType.BOTH, 65, 129);
-    const l3 = new GrDiffLine(GrDiffLineType.BOTH, 66, 130);
-
-    const group = new GrDiffGroup({
-      type: GrDiffGroupType.BOTH,
-      lines: [l1, l2, l3],
-    });
-
-    assert.deepEqual(group.lines, [l1, l2, l3]);
-    assert.deepEqual(group.adds, []);
-    assert.deepEqual(group.removes, []);
-
-    assert.deepEqual(group.lineRange, {
-      left: {start_line: 64, end_line: 66},
-      right: {start_line: 128, end_line: 130},
-    });
-
-    const pairs = group.getSideBySidePairs();
-    assert.deepEqual(pairs, [
-      {left: l1, right: l1},
-      {left: l2, right: l2},
-      {left: l3, right: l3},
-    ]);
-  });
-
-  test('adding delta lines to non-delta group', () => {
-    const l1 = new GrDiffLine(GrDiffLineType.ADD);
-    const l2 = new GrDiffLine(GrDiffLineType.REMOVE);
-    const l3 = new GrDiffLine(GrDiffLineType.BOTH);
-
-    assert.throws(
-      () => new GrDiffGroup({type: GrDiffGroupType.BOTH, lines: [l1, l2, l3]})
-    );
-  });
-
-  suite('hideInContextControl', () => {
-    let groups: GrDiffGroup[];
-    setup(() => {
-      groups = [
-        new GrDiffGroup({
-          type: GrDiffGroupType.BOTH,
-          lines: [
-            new GrDiffLine(GrDiffLineType.BOTH, 5, 7),
-            new GrDiffLine(GrDiffLineType.BOTH, 6, 8),
-            new GrDiffLine(GrDiffLineType.BOTH, 7, 9),
-          ],
-        }),
-        new GrDiffGroup({
-          type: GrDiffGroupType.DELTA,
-          lines: [
-            new GrDiffLine(GrDiffLineType.REMOVE, 8),
-            new GrDiffLine(GrDiffLineType.ADD, 0, 10),
-            new GrDiffLine(GrDiffLineType.REMOVE, 9),
-            new GrDiffLine(GrDiffLineType.ADD, 0, 11),
-            new GrDiffLine(GrDiffLineType.REMOVE, 10),
-            new GrDiffLine(GrDiffLineType.ADD, 0, 12),
-            new GrDiffLine(GrDiffLineType.REMOVE, 11),
-            new GrDiffLine(GrDiffLineType.ADD, 0, 13),
-          ],
-        }),
-        new GrDiffGroup({
-          type: GrDiffGroupType.BOTH,
-          lines: [
-            new GrDiffLine(GrDiffLineType.BOTH, 12, 14),
-            new GrDiffLine(GrDiffLineType.BOTH, 13, 15),
-            new GrDiffLine(GrDiffLineType.BOTH, 14, 16),
-          ],
-        }),
-      ];
-    });
-
-    test('hides hidden groups in context control', () => {
-      const collapsedGroups = hideInContextControl(groups, 3, 7);
-      assert.equal(collapsedGroups.length, 3);
-
-      assert.equal(collapsedGroups[0], groups[0]);
-
-      assert.equal(collapsedGroups[1].type, GrDiffGroupType.CONTEXT_CONTROL);
-      assert.equal(collapsedGroups[1].contextGroups.length, 1);
-      assert.equal(collapsedGroups[1].contextGroups[0], groups[1]);
-
-      assert.equal(collapsedGroups[2], groups[2]);
-    });
-
-    test('splits partially hidden groups', () => {
-      const collapsedGroups = hideInContextControl(groups, 4, 8);
-      assert.equal(collapsedGroups.length, 4);
-      assert.equal(collapsedGroups[0], groups[0]);
-
-      assert.equal(collapsedGroups[1].type, GrDiffGroupType.DELTA);
-      assert.deepEqual(collapsedGroups[1].adds, [groups[1].adds[0]]);
-      assert.deepEqual(collapsedGroups[1].removes, [groups[1].removes[0]]);
-
-      assert.equal(collapsedGroups[2].type, GrDiffGroupType.CONTEXT_CONTROL);
-      assert.equal(collapsedGroups[2].contextGroups.length, 2);
-
-      assert.equal(
-        collapsedGroups[2].contextGroups[0].type,
-        GrDiffGroupType.DELTA
-      );
-      assert.deepEqual(
-        collapsedGroups[2].contextGroups[0].adds,
-        groups[1].adds.slice(1)
-      );
-      assert.deepEqual(
-        collapsedGroups[2].contextGroups[0].removes,
-        groups[1].removes.slice(1)
-      );
-
-      assert.equal(
-        collapsedGroups[2].contextGroups[1].type,
-        GrDiffGroupType.BOTH
-      );
-      assert.deepEqual(collapsedGroups[2].contextGroups[1].lines, [
-        groups[2].lines[0],
-      ]);
-
-      assert.equal(collapsedGroups[3].type, GrDiffGroupType.BOTH);
-      assert.deepEqual(collapsedGroups[3].lines, groups[2].lines.slice(1));
-    });
-
-    suite('with skip chunks', () => {
-      setup(() => {
-        const skipGroup = new GrDiffGroup({
-          type: GrDiffGroupType.BOTH,
-          skip: 60,
-          offsetLeft: 8,
-          offsetRight: 10,
-        });
-        groups = [
-          new GrDiffGroup({
-            type: GrDiffGroupType.BOTH,
-            lines: [
-              new GrDiffLine(GrDiffLineType.BOTH, 5, 7),
-              new GrDiffLine(GrDiffLineType.BOTH, 6, 8),
-              new GrDiffLine(GrDiffLineType.BOTH, 7, 9),
-            ],
-          }),
-          skipGroup,
-          new GrDiffGroup({
-            type: GrDiffGroupType.BOTH,
-            lines: [
-              new GrDiffLine(GrDiffLineType.BOTH, 68, 70),
-              new GrDiffLine(GrDiffLineType.BOTH, 69, 71),
-              new GrDiffLine(GrDiffLineType.BOTH, 70, 72),
-            ],
-          }),
-        ];
-      });
-
-      test('refuses to split skip group when closer to before', () => {
-        const collapsedGroups = hideInContextControl(groups, 4, 10);
-        assert.deepEqual(groups, collapsedGroups);
-      });
-    });
-
-    test('groups unchanged if the hidden range is empty', () => {
-      assert.deepEqual(hideInContextControl(groups, 0, 0), groups);
-    });
-
-    test('groups unchanged if there is only 1 line to hide', () => {
-      assert.deepEqual(hideInContextControl(groups, 3, 4), groups);
-    });
-  });
-
-  suite('isTotal', () => {
-    test('is total for add', () => {
-      const lines = [];
-      for (let idx = 0; idx < 10; idx++) {
-        lines.push(new GrDiffLine(GrDiffLineType.ADD));
-      }
-      const group = new GrDiffGroup({type: GrDiffGroupType.DELTA, lines});
-      assert.isTrue(group.isTotal());
-    });
-
-    test('is total for remove', () => {
-      const lines = [];
-      for (let idx = 0; idx < 10; idx++) {
-        lines.push(new GrDiffLine(GrDiffLineType.REMOVE));
-      }
-      const group = new GrDiffGroup({type: GrDiffGroupType.DELTA, lines});
-      assert.isTrue(group.isTotal());
-    });
-
-    test('not total for non-delta', () => {
-      const lines = [];
-      for (let idx = 0; idx < 10; idx++) {
-        lines.push(new GrDiffLine(GrDiffLineType.BOTH));
-      }
-      const group = new GrDiffGroup({type: GrDiffGroupType.DELTA, lines});
-      assert.isFalse(group.isTotal());
-    });
-  });
-
-  suite('startLine', () => {
-    test('DELTA', () => {
-      const lines: GrDiffLine[] = [];
-      lines.push(new GrDiffLine(GrDiffLineType.BOTH, 3, 4));
-      const group = new GrDiffGroup({type: GrDiffGroupType.DELTA, lines});
-      assert.equal(group.startLine(Side.LEFT), 3);
-      assert.equal(group.startLine(Side.RIGHT), 4);
-    });
-
-    test('CONTEXT CONTROL', () => {
-      const lines: GrDiffLine[] = [];
-      lines.push(new GrDiffLine(GrDiffLineType.BOTH, 3, 4));
-      const delta = new GrDiffGroup({type: GrDiffGroupType.DELTA, lines});
-      const group = new GrDiffGroup({
-        type: GrDiffGroupType.CONTEXT_CONTROL,
-        contextGroups: [delta],
-      });
-      assert.equal(group.startLine(Side.LEFT), 3);
-      assert.equal(group.startLine(Side.RIGHT), 4);
-    });
-
-    test('SKIP', () => {
-      const group = new GrDiffGroup({
-        type: GrDiffGroupType.BOTH,
-        skip: 10,
-        offsetLeft: 3,
-        offsetRight: 6,
-      });
-      assert.equal(group.startLine(Side.LEFT), 3);
-      assert.equal(group.startLine(Side.RIGHT), 6);
-
-      const group2 = new GrDiffGroup({
-        type: GrDiffGroupType.BOTH,
-        skip: 0,
-        offsetLeft: 3,
-        offsetRight: 6,
-      });
-      assert.equal(group2.startLine(Side.LEFT), 3);
-      assert.equal(group2.startLine(Side.RIGHT), 6);
-    });
-
-    test('FILE', () => {
-      const lines: GrDiffLine[] = [];
-      lines.push(new GrDiffLine(GrDiffLineType.BOTH, FILE, FILE));
-      const group = new GrDiffGroup({type: GrDiffGroupType.DELTA, lines});
-      assert.equal(group.startLine(Side.LEFT), FILE);
-      assert.equal(group.startLine(Side.RIGHT), FILE);
-    });
-
-    test('LOST', () => {
-      const lines: GrDiffLine[] = [];
-      lines.push(new GrDiffLine(GrDiffLineType.BOTH, LOST, LOST));
-      const group = new GrDiffGroup({type: GrDiffGroupType.DELTA, lines});
-      assert.equal(group.startLine(Side.LEFT), LOST);
-      assert.equal(group.startLine(Side.RIGHT), LOST);
-    });
-  });
-});
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff-line.ts b/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff-line.ts
deleted file mode 100644
index 1a89207..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff-line.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * @license
- * Copyright 2016 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import {
-  FILE,
-  GrDiffLine as GrDiffLineApi,
-  GrDiffLineType,
-  LineNumber,
-  Side,
-} from '../../../api/diff';
-
-export class GrDiffLine implements GrDiffLineApi {
-  constructor(
-    readonly type: GrDiffLineType,
-    public beforeNumber: LineNumber = 0,
-    public afterNumber: LineNumber = 0
-  ) {}
-
-  hasIntralineInfo = false;
-
-  highlights: Highlights[] = [];
-
-  text = '';
-
-  lineNumber(side: Side) {
-    return side === Side.LEFT ? this.beforeNumber : this.afterNumber;
-  }
-
-  // TODO(TS): remove this properties
-  static readonly Type = GrDiffLineType;
-
-  static readonly File = FILE;
-}
-
-/**
- * A line highlight object consists of three fields:
- * - contentIndex: The index of the chunk `content` field (the line
- *   being referred to).
- * - startIndex: Index of the character where the highlight should begin.
- * - endIndex: (optional) Index of the character where the highlight should
- *   end. If omitted, the highlight is meant to be a continuation onto the
- *   next line.
- */
-export interface Highlights {
-  contentIndex: number;
-  startIndex: number;
-  endIndex?: number;
-}
-
-export const BLANK_LINE = new GrDiffLine(GrDiffLineType.BLANK);
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff-styles.ts b/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff-styles.ts
deleted file mode 100644
index a6dddd64..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff-styles.ts
+++ /dev/null
@@ -1,671 +0,0 @@
-/**
- * @license
- * Copyright 2023 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import {css} from 'lit';
-
-export const grDiffStyles = css`
-  /* This is used to hide all left side of the diff (e.g. diffs besides
-     comments in the change log). Since we want to remove the first 4
-     cells consistently in all rows except context buttons (.dividerRow). */
-  :host(.no-left) .sideBySide colgroup col:nth-child(-n + 4),
-  :host(.no-left) .sideBySide tr:not(.dividerRow) td:nth-child(-n + 4) {
-    display: none;
-  }
-  :host(.disable-context-control-buttons) {
-    --context-control-display: none;
-  }
-  :host(.disable-context-control-buttons) .section {
-    border-right: none;
-  }
-  :host(.hide-line-length-indicator) .full-width td.content .contentText {
-    background-image: none;
-  }
-
-  :host {
-    font-family: var(--monospace-font-family, ''), 'Roboto Mono';
-    font-size: var(--font-size, var(--font-size-code, 12px));
-    /* usually 16px = 12px + 4px */
-    line-height: calc(
-      var(--font-size, var(--font-size-code, 12px)) + var(--spacing-s, 4px)
-    );
-  }
-
-  .thread-group {
-    display: block;
-    max-width: var(--content-width, 80ch);
-    white-space: normal;
-    background-color: var(--diff-blank-background-color);
-  }
-  .diffContainer {
-    max-width: var(--diff-max-width, none);
-    font-family: var(--monospace-font-family);
-  }
-  table {
-    border-collapse: collapse;
-    table-layout: fixed;
-  }
-  td.lineNum {
-    /* Enforces background whenever lines wrap */
-    background-color: var(--diff-blank-background-color);
-  }
-
-  /* Provides the option to add side borders (left and right) to the line
-     number column. */
-  td.lineNum,
-  td.blankLineNum,
-  td.moveControlsLineNumCol,
-  td.contextLineNum {
-    box-shadow: var(--line-number-box-shadow, unset);
-  }
-
-  /* Context controls break up the table visually, so we set the right
-     border on individual sections to leave a gap for the divider.
-
-     Also taken into account for max-width calculations in SHRINK_ONLY mode
-     (check GrDiff.updatePreferenceStyles). */
-  .section {
-    border-right: 1px solid var(--border-color);
-  }
-  .section.contextControl {
-    /* Divider inside this section must not have border; we set borders on
-       the padding rows below. */
-    border-right-width: 0;
-  }
-  /* Padding rows behind context controls. The diff is styled to be cut
-     into two halves by the negative space of the divider on which the
-     context control buttons are anchored. */
-  .contextBackground {
-    border-right: 1px solid var(--border-color);
-  }
-  .contextBackground.above {
-    border-bottom: 1px solid var(--border-color);
-  }
-  .contextBackground.below {
-    border-top: 1px solid var(--border-color);
-  }
-
-  .lineNumButton {
-    display: block;
-    width: 100%;
-    height: 100%;
-    background-color: var(--diff-blank-background-color);
-    box-shadow: var(--line-number-box-shadow, unset);
-  }
-  td.lineNum {
-    vertical-align: top;
-  }
-
-  /* The only way to focus this (clicking) will apply our own focus
-     styling, so this default styling is not needed and distracting. */
-  .lineNumButton:focus {
-    outline: none;
-  }
-  gr-image-viewer {
-    width: 100%;
-    height: 100%;
-    max-width: var(--image-viewer-max-width, 95vw);
-    max-height: var(--image-viewer-max-height, 90vh);
-    /* Defined by paper-styles default-theme and used in various
-       components. background-color-secondary is a compromise between
-       fairly light in light theme (where we ideally would want
-       background-color-primary) yet slightly offset against the app
-       background in dark mode, where drop shadows e.g. around paper-card
-       are almost invisible. */
-    --primary-background-color: var(--background-color-secondary);
-  }
-  .image-diff .gr-diff {
-    text-align: center;
-  }
-  .image-diff img {
-    box-shadow: var(--elevation-level-1);
-    max-width: 50em;
-  }
-  .image-diff .right.lineNumButton {
-    border-left: 1px solid var(--border-color);
-  }
-  .image-diff label {
-    font-family: var(--font-family);
-    font-style: italic;
-  }
-  tbody.binary-diff td {
-    font-family: var(--font-family);
-    font-style: italic;
-    text-align: center;
-    padding: var(--spacing-s) 0;
-  }
-  .diff-row {
-    outline: none;
-    user-select: none;
-  }
-  .diff-row.target-row.target-side-left .lineNumButton.left,
-  .diff-row.target-row.target-side-right .lineNumButton.right,
-  .diff-row.target-row.unified .lineNumButton {
-    color: var(--primary-text-color);
-  }
-
-  /* Preparing selected line cells with position relative so it allows a
-     positioned overlay with 'position: absolute'. */
-  .target-row td {
-    position: relative;
-  }
-
-  /* Defines an overlay to the selected line for drawing an outline without
-     blocking user interaction (e.g. text selection). */
-  .target-row td::before {
-    border-width: 0;
-    border-style: solid;
-    border-color: var(--focused-line-outline-color);
-    position: absolute;
-    top: 0;
-    left: 0;
-    width: 100%;
-    height: 100%;
-    pointer-events: none;
-    user-select: none;
-    content: ' ';
-  }
-
-  /* The outline for the selected content cell should be the same in all
-     cases. */
-  .target-row.target-side-left td.left.content::before,
-  .target-row.target-side-right td.right.content::before,
-  .unified.target-row td.content::before {
-    border-width: 1px 1px 1px 0;
-  }
-
-  /* The outline for the sign cell should be always be contiguous
-     top/bottom. */
-  .target-row.target-side-left td.left.sign::before,
-  .target-row.target-side-right td.right.sign::before {
-    border-width: 1px 0;
-  }
-
-  /* For side-by-side we need to select the correct line number to
-     "visually close" the outline. */
-  .side-by-side.target-row.target-side-left td.left.lineNum::before,
-  .side-by-side.target-row.target-side-right td.right.lineNum::before {
-    border-width: 1px 0 1px 1px;
-  }
-
-  /* For unified diff we always start the overlay from the left cell. */
-  .unified.target-row td.left:not(.content)::before {
-    border-width: 1px 0 1px 1px;
-  }
-
-  /* For unified diff we should continue the top/bottom border in right
-     line number column. */
-  .unified.target-row td.right:not(.content)::before {
-    border-width: 1px 0;
-  }
-
-  .content {
-    background-color: var(--diff-blank-background-color);
-  }
-
-  /* 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. */
-  .semantic-token.navigable {
-    text-decoration-style: dotted;
-    text-decoration-line: underline;
-  }
-  .semantic-token.navigable.clickable {
-    text-decoration-style: solid;
-    cursor: pointer;
-  }
-
-  /* The file line, which has no contentText, add some margin before the
-     first comment. We cannot add padding the container because we only
-     want it if there is at least one comment thread, and the slotting
-     makes :empty not work as expected. */
-  .content.file slot:first-child::slotted(.comment-thread) {
-    display: block;
-    margin-top: var(--spacing-xs);
-  }
-  .contentText {
-    background-color: var(--view-background-color);
-  }
-  .blank {
-    background-color: var(--diff-blank-background-color);
-  }
-  .image-diff .content {
-    background-color: var(--diff-blank-background-color);
-  }
-  .responsive {
-    width: 100%;
-  }
-  .responsive .contentText {
-    white-space: break-spaces;
-    word-break: break-all;
-  }
-  .lineNumButton,
-  .content {
-    vertical-align: top;
-    white-space: pre;
-  }
-  .contextLineNum,
-  .lineNumButton {
-    -webkit-user-select: none;
-    -moz-user-select: none;
-    -ms-user-select: none;
-    user-select: none;
-
-    color: var(--deemphasized-text-color);
-    padding: 0 var(--spacing-m);
-    text-align: right;
-  }
-  .canComment .lineNumButton {
-    cursor: pointer;
-  }
-  .sign {
-    min-width: 1ch;
-    width: 1ch;
-    background-color: var(--view-background-color);
-  }
-  .sign.blank {
-    background-color: var(--diff-blank-background-color);
-  }
-  .content {
-    /* Set min width since setting width on table cells still allows them
-       to shrink. Do not set max width because CJK
-       (Chinese-Japanese-Korean) glyphs have variable width. */
-    min-width: var(--content-width, 80ch);
-    width: var(--content-width, 80ch);
-  }
-  /* If there are no intraline info, consider everything changed */
-  .content.add .contentText .intraline,
-  .content.add.no-intraline-info .contentText,
-  .sign.add.no-intraline-info,
-  .delta.total .content.add .contentText {
-    background-color: var(--dark-add-highlight-color);
-  }
-  .content.add .contentText,
-  .sign.add {
-    background-color: var(--light-add-highlight-color);
-  }
-  /* If there are no intraline info, consider everything changed */
-  .content.remove .contentText .intraline,
-  .content.remove.no-intraline-info .contentText,
-  .delta.total .content.remove .contentText,
-  .sign.remove.no-intraline-info {
-    background-color: var(--dark-remove-highlight-color);
-  }
-  .content.remove .contentText,
-  .sign.remove {
-    background-color: var(--light-remove-highlight-color);
-  }
-
-  .ignoredWhitespaceOnly .sign.no-intraline-info {
-    background-color: var(--view-background-color);
-  }
-
-  /* dueToRebase */
-  .dueToRebase .content.add .contentText .intraline,
-  .delta.total.dueToRebase .content.add .contentText {
-    background-color: var(--dark-rebased-add-highlight-color);
-  }
-  .dueToRebase .content.add .contentText {
-    background-color: var(--light-rebased-add-highlight-color);
-  }
-  .dueToRebase .content.remove .contentText .intraline,
-  .delta.total.dueToRebase .content.remove .contentText {
-    background-color: var(--dark-rebased-remove-highlight-color);
-  }
-  .dueToRebase .content.remove .contentText {
-    background-color: var(--light-rebased-remove-highlight-color);
-  }
-
-  /* dueToMove */
-  .dueToMove .sign.add,
-  .dueToMove .content.add .contentText,
-  .dueToMove .moveControls.movedIn .sign.right,
-  .dueToMove .moveControls.movedIn .moveHeader,
-  .delta.total.dueToMove .content.add .contentText {
-    background-color: var(--diff-moved-in-background);
-  }
-
-  .dueToMove.changed .sign.add,
-  .dueToMove.changed .content.add .contentText,
-  .dueToMove.changed .moveControls.movedIn .sign.right,
-  .dueToMove.changed .moveControls.movedIn .moveHeader,
-  .delta.total.dueToMove.changed .content.add .contentText {
-    background-color: var(--diff-moved-in-changed-background);
-  }
-
-  .dueToMove .sign.remove,
-  .dueToMove .content.remove .contentText,
-  .dueToMove .moveControls.movedOut .moveHeader,
-  .dueToMove .moveControls.movedOut .sign.left,
-  .delta.total.dueToMove .content.remove .contentText {
-    background-color: var(--diff-moved-out-background);
-  }
-
-  .delta.dueToMove .movedIn .moveHeader {
-    --gr-range-header-color: var(--diff-moved-in-label-color);
-  }
-  .delta.dueToMove.changed .movedIn .moveHeader {
-    --gr-range-header-color: var(--diff-moved-in-changed-label-color);
-  }
-  .delta.dueToMove .movedOut .moveHeader {
-    --gr-range-header-color: var(--diff-moved-out-label-color);
-  }
-
-  .moveHeader a {
-    color: inherit;
-  }
-
-  /* ignoredWhitespaceOnly */
-  .ignoredWhitespaceOnly .content.add .contentText .intraline,
-  .delta.total.ignoredWhitespaceOnly .content.add .contentText,
-  .ignoredWhitespaceOnly .content.add .contentText,
-  .ignoredWhitespaceOnly .content.remove .contentText .intraline,
-  .delta.total.ignoredWhitespaceOnly .content.remove .contentText,
-  .ignoredWhitespaceOnly .content.remove .contentText {
-    background-color: var(--view-background-color);
-  }
-
-  .content .contentText gr-diff-text:empty:after,
-  .content .contentText gr-legacy-text:empty:after,
-  .content .contentText:empty:after {
-    /* Newline, to ensure empty lines are one line-height tall. */
-    content: '\\A';
-  }
-
-  /* Context controls */
-  .contextControl {
-    display: var(--context-control-display, table-row-group);
-    background-color: transparent;
-    border: none;
-    --divider-height: var(--spacing-s);
-    --divider-border: 1px;
-  }
-  /* TODO: Is this still used? */
-  .contextControl gr-button gr-icon {
-    /* should match line-height of gr-button */
-    font-size: var(--line-height-mono, 18px);
-  }
-  .contextControl td:not(.lineNumButton) {
-    text-align: center;
-  }
-
-  /* Padding rows behind context controls. Styled as a continuation of the
-     line gutters and code area. */
-  .contextBackground > .contextLineNum {
-    background-color: var(--diff-blank-background-color);
-  }
-  .contextBackground > td:not(.contextLineNum) {
-    background-color: var(--view-background-color);
-  }
-  .contextBackground {
-    /* One line of background behind the context expanders which they can
-       render on top of, plus some padding. */
-    height: calc(var(--line-height-normal) + var(--spacing-s));
-  }
-
-  .dividerCell {
-    vertical-align: top;
-  }
-  .dividerRow.show-both .dividerCell {
-    height: var(--divider-height);
-  }
-  .dividerRow.show-above .dividerCell,
-  .dividerRow.show-above .dividerCell {
-    height: 0;
-  }
-
-  .br:after {
-    /* Line feed */
-    content: '\\A';
-  }
-  .tab {
-    display: inline-block;
-  }
-  .tab-indicator:before {
-    color: var(--diff-tab-indicator-color);
-    /* >> character */
-    content: '\\00BB';
-    position: absolute;
-  }
-  .special-char-indicator {
-    /* spacing so elements don't collide */
-    padding-right: var(--spacing-m);
-  }
-  .special-char-indicator:before {
-    color: var(--diff-tab-indicator-color);
-    content: '•';
-    position: absolute;
-  }
-  .special-char-warning {
-    /* spacing so elements don't collide */
-    padding-right: var(--spacing-m);
-  }
-  .special-char-warning:before {
-    color: var(--warning-foreground);
-    content: '!';
-    position: absolute;
-  }
-  /* Is defined after other background-colors, such that this
-     rule wins in case of same specificity. */
-  .trailing-whitespace,
-  .content .contentText .trailing-whitespace,
-  .trailing-whitespace .intraline,
-  .content .contentText .trailing-whitespace .intraline {
-    border-radius: var(--border-radius, 4px);
-    background-color: var(--diff-trailing-whitespace-indicator);
-  }
-  #diffHeader {
-    background-color: var(--table-header-background-color);
-    border-bottom: 1px solid var(--border-color);
-    color: var(--link-color);
-    padding: var(--spacing-m) 0 var(--spacing-m) 48px;
-  }
-  #diffTable {
-    /* for gr-selection-action-box positioning */
-    position: relative;
-  }
-  #diffTable:focus {
-    outline: none;
-  }
-  #loadingError,
-  #sizeWarning {
-    display: block;
-    margin: var(--spacing-l) auto;
-    max-width: 60em;
-    text-align: center;
-  }
-  #loadingError {
-    color: var(--error-text-color);
-  }
-  #sizeWarning gr-button {
-    margin: var(--spacing-l);
-  }
-  .target-row td.blame {
-    background: var(--diff-selection-background-color);
-  }
-  td.lost div {
-    background-color: var(--info-background);
-  }
-  td.lost div.lost-message {
-    font-family: var(--font-family, 'Roboto');
-    font-size: var(--font-size-normal, 14px);
-    line-height: var(--line-height-normal);
-    padding: var(--spacing-s) 0;
-  }
-  td.lost div.lost-message gr-icon {
-    padding: 0 var(--spacing-s) 0 var(--spacing-m);
-    color: var(--blue-700);
-  }
-
-  col.sign,
-  td.sign {
-    display: none;
-  }
-
-  /* Sign column should only be shown in high-contrast mode. */
-  :host(.with-sign-col) col.sign {
-    display: table-column;
-  }
-  :host(.with-sign-col) td.sign {
-    display: table-cell;
-  }
-  col.blame {
-    display: none;
-  }
-  td.blame {
-    display: none;
-    padding: 0 var(--spacing-m);
-    white-space: pre;
-  }
-  :host(.showBlame) col.blame {
-    display: table-column;
-  }
-  :host(.showBlame) td.blame {
-    display: table-cell;
-  }
-  td.blame > span {
-    opacity: 0.6;
-  }
-  td.blame > span.startOfRange {
-    opacity: 1;
-  }
-  td.blame .blameDate {
-    font-family: var(--monospace-font-family);
-    color: var(--link-color);
-    text-decoration: none;
-  }
-  .responsive td.blame {
-    overflow: hidden;
-    width: 200px;
-  }
-  /** Support the line length indicator **/
-  .responsive td.content .contentText {
-    /* Same strategy as in
-       https://stackoverflow.com/questions/1179928/how-can-i-put-a-vertical-line-down-the-center-of-a-div
-       */
-    background-image: linear-gradient(
-      var(--line-length-indicator-color),
-      var(--line-length-indicator-color)
-    );
-    background-size: 1px 100%;
-    background-position: var(--line-limit-marker) 0;
-    background-repeat: no-repeat;
-  }
-  .newlineWarning {
-    color: var(--deemphasized-text-color);
-    text-align: center;
-  }
-  .newlineWarning.hidden {
-    display: none;
-  }
-  .lineNum.COVERED .lineNumButton {
-    color: var(
-      --coverage-covered-line-num-color,
-      var(--deemphasized-text-color)
-    );
-    background-color: var(--coverage-covered, #e0f2f1);
-  }
-  .lineNum.NOT_COVERED .lineNumButton {
-    color: var(
-      --coverage-covered-line-num-color,
-      var(--deemphasized-text-color)
-    );
-    background-color: var(--coverage-not-covered, #ffd1a4);
-  }
-  .lineNum.PARTIALLY_COVERED .lineNumButton {
-    color: var(
-      --coverage-covered-line-num-color,
-      var(--deemphasized-text-color)
-    );
-    background: linear-gradient(
-      to right bottom,
-      var(--coverage-not-covered, #ffd1a4) 0%,
-      var(--coverage-not-covered, #ffd1a4) 50%,
-      var(--coverage-covered, #e0f2f1) 50%,
-      var(--coverage-covered, #e0f2f1) 100%
-    );
-  }
-
-  // TODO: Investigate whether this CSS is still necessary.
-  /* BEGIN: Select and copy for Polymer 2 */
-  /* Below was copied and modified from the original css in gr-diff-selection.html. */
-  .content,
-  .contextControl,
-  .blame {
-    -webkit-user-select: none;
-    -moz-user-select: none;
-    -ms-user-select: none;
-    user-select: none;
-  }
-
-  .selected-left:not(.selected-comment)
-    .side-by-side
-    .left
-    + .content
-    .contentText,
-  .selected-right:not(.selected-comment)
-    .side-by-side
-    .right
-    + .content
-    .contentText,
-  .selected-left:not(.selected-comment)
-    .unified
-    .left.lineNum
-    ~ .content:not(.both)
-    .contentText,
-  .selected-right:not(.selected-comment)
-    .unified
-    .right.lineNum
-    ~ .content
-    .contentText,
-  .selected-left.selected-comment .side-by-side .left + .content .message,
-  .selected-right.selected-comment
-    .side-by-side
-    .right
-    + .content
-    .message
-    :not(.collapsedContent),
-  .selected-comment .unified .message :not(.collapsedContent),
-  .selected-blame .blame {
-    -webkit-user-select: text;
-    -moz-user-select: text;
-    -ms-user-select: text;
-    user-select: text;
-  }
-
-  /* Make comments and check results selectable when selected */
-  .selected-left.selected-comment ::slotted(.comment-thread[diff-side='left']),
-  .selected-right.selected-comment
-    ::slotted(.comment-thread[diff-side='right']) {
-    -webkit-user-select: text;
-    -moz-user-select: text;
-    -ms-user-select: text;
-    user-select: text;
-  }
-  /* END: Select and copy for Polymer 2 */
-
-  .whitespace-change-only-message {
-    background-color: var(--diff-context-control-background-color);
-    border: 1px solid var(--diff-context-control-border-color);
-    text-align: center;
-  }
-
-  .token-highlight {
-    background-color: var(--token-highlighting-color, #fffd54);
-  }
-
-  gr-selection-action-box {
-    /* Needs z-index to appear above wrapped content, since it's inserted
-       into DOM before it. */
-    z-index: 120;
-  }
-
-  gr-diff-image-new,
-  gr-diff-image-old,
-  gr-diff-section,
-  gr-context-controls-section,
-  gr-diff-row {
-    display: contents;
-  }
-`;
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff.ts b/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff.ts
deleted file mode 100644
index 47ed7cf..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff.ts
+++ /dev/null
@@ -1,1127 +0,0 @@
-/**
- * @license
- * Copyright 2015 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import '../../../styles/shared-styles';
-import '../../../elements/shared/gr-button/gr-button';
-import '../../../elements/shared/gr-icon/gr-icon';
-import '../gr-diff-builder/gr-diff-builder-element';
-import '../gr-diff-highlight/gr-diff-highlight';
-import '../gr-diff-selection/gr-diff-selection';
-import '../../diff/gr-syntax-themes/gr-syntax-theme';
-import '../../diff/gr-ranged-comment-themes/gr-ranged-comment-theme';
-import '../../diff/gr-ranged-comment-hint/gr-ranged-comment-hint';
-import {
-  getLine,
-  getLineElByChild,
-  getLineNumber,
-  getRange,
-  getSide,
-  GrDiffThreadElement,
-  isLongCommentRange,
-  isThreadEl,
-  rangesEqual,
-  getResponsiveMode,
-  isResponsive,
-  isNewDiff,
-  getDataFromCommentThreadEl,
-  GrDiffCommentThread,
-} from '../../diff/gr-diff/gr-diff-utils';
-import {BlameInfo, CommentRange, ImageInfo} from '../../../types/common';
-import {DiffInfo, DiffPreferencesInfo} from '../../../types/diff';
-import {
-  CreateRangeCommentEventDetail,
-  GrDiffHighlight,
-} from '../gr-diff-highlight/gr-diff-highlight';
-import {
-  GrDiffBuilderElement,
-  getLineNumberCellWidth,
-} from '../gr-diff-builder/gr-diff-builder-element';
-import {CoverageRange, DiffLayer} from '../../../types/types';
-import {CommentRangeLayer} from '../../diff/gr-ranged-comment-layer/gr-ranged-comment-layer';
-import {
-  createDefaultDiffPrefs,
-  DiffViewMode,
-  Side,
-} from '../../../constants/constants';
-import {KeyLocations} from '../gr-diff-processor/gr-diff-processor';
-import {fire, fireAlert} from '../../../utils/event-util';
-import {MovedLinkClickedEvent, ValueChangedEvent} from '../../../types/events';
-import {getContentEditableRange} from '../../../utils/safari-selection-util';
-import {AbortStop} from '../../../api/core';
-import {
-  RenderPreferences,
-  GrDiff as GrDiffApi,
-  DisplayLine,
-  LineNumber,
-  LOST,
-} from '../../../api/diff';
-import {isSafari, toggleClass} from '../../../utils/dom-util';
-import {assertIsDefined} from '../../../utils/common-util';
-import {
-  debounceP,
-  DelayedPromise,
-  DELAYED_CANCELLATION,
-} from '../../../utils/async-util';
-import {GrDiffSelection} from '../gr-diff-selection/gr-diff-selection';
-import {property, query, state} from 'lit/decorators.js';
-import {sharedStyles} from '../../../styles/shared-styles';
-import {html, LitElement, nothing, PropertyValues} from 'lit';
-import {when} from 'lit/directives/when.js';
-import {grSyntaxTheme} from '../../diff/gr-syntax-themes/gr-syntax-theme';
-import {grRangedCommentTheme} from '../../diff/gr-ranged-comment-themes/gr-ranged-comment-theme';
-import {classMap} from 'lit/directives/class-map.js';
-import {iconStyles} from '../../../styles/gr-icon-styles';
-import {expandFileMode} from '../../../utils/file-util';
-import {DiffModel, diffModelToken} from '../gr-diff-model/gr-diff-model';
-import {provide} from '../../../models/dependency';
-import {grDiffStyles} from './gr-diff-styles';
-import {getDiffLength} from '../../../utils/diff-util';
-
-const NO_NEWLINE_LEFT = 'No newline at end of left file.';
-const NO_NEWLINE_RIGHT = 'No newline at end of right file.';
-
-const LARGE_DIFF_THRESHOLD_LINES = 10000;
-const FULL_CONTEXT = -1;
-
-const COMMIT_MSG_PATH = '/COMMIT_MSG';
-/**
- * 72 is the unofficial length standard for git commit messages.
- * Derived from the fact that git log/show appends 4 ws in the beginning of
- * each line when displaying commit messages. To center the commit message
- * in an 80 char terminal a 4 ws border is added to the rightmost side:
- * 4 + 72 + 4
- */
-const COMMIT_MSG_LINE_LENGTH = 72;
-
-export class GrDiff extends LitElement implements GrDiffApi {
-  /**
-   * Fired when the user selects a line.
-   *
-   * @event line-selected
-   */
-
-  /**
-   * Fired if being logged in is required.
-   *
-   * @event show-auth-required
-   */
-
-  /**
-   * Fired when a comment is created
-   *
-   * @event create-comment
-   */
-
-  /**
-   * Fired when rendering, including syntax highlighting, is done. Also fired
-   * when no rendering can be done because required preferences are not set.
-   *
-   * @event render
-   */
-
-  /**
-   * Fired for interaction reporting when a diff context is expanded.
-   * Contains an event.detail with numLines about the number of lines that
-   * were expanded.
-   *
-   * @event diff-context-expanded
-   */
-
-  @query('#diffTable')
-  diffTable?: HTMLTableElement;
-
-  @property({type: Boolean})
-  noAutoRender = false;
-
-  @property({type: String})
-  path?: string;
-
-  @property({type: Object})
-  prefs?: DiffPreferencesInfo;
-
-  @property({type: Object})
-  renderPrefs: RenderPreferences = {};
-
-  @property({type: Boolean, reflect: true})
-  override hidden = false;
-
-  @property({type: Boolean})
-  noRenderOnPrefsChange?: boolean;
-
-  // Private but used in tests.
-  @state()
-  commentRanges: CommentRangeLayer[] = [];
-
-  // explicitly highlight a range if it is not associated with any comment
-  @property({type: Object})
-  highlightRange?: CommentRange;
-
-  @property({type: Array})
-  coverageRanges: CoverageRange[] = [];
-
-  @property({type: Boolean})
-  lineWrapping = false;
-
-  @property({type: String})
-  viewMode = DiffViewMode.SIDE_BY_SIDE;
-
-  @property({type: Object})
-  lineOfInterest?: DisplayLine;
-
-  /**
-   * True when diff is changed, until the content is done rendering.
-   * Use getter/setter loading instead of this.
-   */
-  private _loading = true;
-
-  get loading() {
-    return this._loading;
-  }
-
-  set loading(loading: boolean) {
-    if (this._loading === loading) return;
-    const oldLoading = this._loading;
-    this._loading = loading;
-    fire(this, 'loading-changed', {value: this._loading});
-    this.requestUpdate('loading', oldLoading);
-  }
-
-  @property({type: Boolean})
-  loggedIn = false;
-
-  @property({type: Object})
-  diff?: DiffInfo;
-
-  @state()
-  private diffTableClass = '';
-
-  @property({type: Object})
-  baseImage?: ImageInfo;
-
-  @property({type: Object})
-  revisionImage?: ImageInfo;
-
-  /**
-   * In order to allow multi-select in Safari browsers, a workaround is required
-   * to trigger 'beforeinput' events to get a list of static ranges. This is
-   * obtained by making the content of the diff table "contentEditable".
-   */
-  @property({type: Boolean})
-  override isContentEditable = isSafari();
-
-  /**
-   * Whether the safety check for large diffs when whole-file is set has
-   * been bypassed. If the value is null, then the safety has not been
-   * bypassed. If the value is a number, then that number represents the
-   * context preference to use when rendering the bypassed diff.
-   *
-   * Private but used in tests.
-   */
-  @state()
-  safetyBypass: number | null = null;
-
-  // Private but used in tests.
-  @state()
-  showWarning?: boolean;
-
-  @property({type: String})
-  errorMessage: string | null = null;
-
-  @property({type: Array})
-  blame: BlameInfo[] | null = null;
-
-  @property({type: Boolean})
-  showNewlineWarningLeft = false;
-
-  @property({type: Boolean})
-  showNewlineWarningRight = false;
-
-  @property({type: Boolean})
-  useNewImageDiffUi = false;
-
-  // Private but used in tests.
-  @state()
-  diffLength?: number;
-
-  /**
-   * Observes comment nodes added or removed at any point.
-   * Can be used to unregister upon detachment.
-   */
-  private nodeObserver?: MutationObserver;
-
-  @property({type: Array})
-  layers?: DiffLayer[];
-
-  // Private but used in tests.
-  renderDiffTableTask?: DelayedPromise<void>;
-
-  // Private but used in tests.
-  diffSelection = new GrDiffSelection();
-
-  // Private but used in tests.
-  highlights = new GrDiffHighlight();
-
-  // Private but used in tests.
-  diffBuilder = new GrDiffBuilderElement();
-
-  private diffModel = new DiffModel(undefined);
-
-  static override get styles() {
-    return [
-      iconStyles,
-      sharedStyles,
-      grSyntaxTheme,
-      grRangedCommentTheme,
-      grDiffStyles,
-    ];
-  }
-
-  constructor() {
-    super();
-    provide(this, diffModelToken, () => this.diffModel);
-    this.addEventListener(
-      'create-range-comment',
-      (e: CustomEvent<CreateRangeCommentEventDetail>) =>
-        this.handleCreateRangeComment(e)
-    );
-    this.addEventListener('render-content', () => this.handleRenderContent());
-    this.addEventListener('moved-link-clicked', (e: MovedLinkClickedEvent) => {
-      this.dispatchSelectedLine(e.detail.lineNum, e.detail.side);
-    });
-  }
-
-  override connectedCallback() {
-    super.connectedCallback();
-    if (this.loggedIn) {
-      this.addSelectionListeners();
-    }
-    if (this.diff && this.diffTable) {
-      this.diffSelection.init(this.diff, this.diffTable);
-    }
-    if (this.diffTable && this.diffBuilder) {
-      this.highlights.init(this.diffTable, this.diffBuilder);
-    }
-    this.diffBuilder.init();
-  }
-
-  override disconnectedCallback() {
-    this.removeSelectionListeners();
-    this.renderDiffTableTask?.cancel();
-    this.diffSelection.cleanup();
-    this.highlights.cleanup();
-    this.diffBuilder.cleanup();
-    super.disconnectedCallback();
-  }
-
-  protected override willUpdate(changedProperties: PropertyValues<this>): void {
-    if (
-      changedProperties.has('path') ||
-      changedProperties.has('lineWrapping') ||
-      changedProperties.has('viewMode') ||
-      changedProperties.has('useNewImageDiffUi') ||
-      changedProperties.has('prefs')
-    ) {
-      this.prefsChanged();
-    }
-    if (changedProperties.has('blame')) {
-      this.blameChanged();
-    }
-    if (changedProperties.has('renderPrefs')) {
-      this.renderPrefsChanged();
-    }
-    if (changedProperties.has('loggedIn')) {
-      if (this.loggedIn && this.isConnected) {
-        this.addSelectionListeners();
-      } else {
-        this.removeSelectionListeners();
-      }
-    }
-    if (changedProperties.has('coverageRanges')) {
-      this.diffBuilder.updateCoverageRanges(this.coverageRanges);
-    }
-    if (changedProperties.has('lineOfInterest')) {
-      this.lineOfInterestChanged();
-    }
-  }
-
-  protected override updated(changedProperties: PropertyValues<this>): void {
-    if (changedProperties.has('diff')) {
-      // diffChanged relies on diffTable ahving been rendered.
-      this.diffChanged();
-    }
-  }
-
-  override render() {
-    return html`
-      ${this.renderHeader()} ${this.renderContainer()}
-      ${this.renderNewlineWarning()} ${this.renderLoadingError()}
-      ${this.renderSizeWarning()}
-    `;
-  }
-
-  private renderHeader() {
-    const diffheaderItems = this.computeDiffHeaderItems();
-    if (diffheaderItems.length === 0) return nothing;
-    return html`
-      <div id="diffHeader">
-        ${diffheaderItems.map(item => html`<div>${item}</div>`)}
-      </div>
-    `;
-  }
-
-  private renderContainer() {
-    const cssClasses = {
-      oldDiff: true,
-      diffContainer: true,
-      unified: this.viewMode === DiffViewMode.UNIFIED,
-      sideBySide: this.viewMode === DiffViewMode.SIDE_BY_SIDE,
-      canComment: this.loggedIn,
-    };
-    return html`
-      <div class=${classMap(cssClasses)} @click=${this.handleTap}>
-        <table
-          id="diffTable"
-          class=${this.diffTableClass}
-          ?contenteditable=${this.isContentEditable}
-        ></table>
-        ${when(
-          this.showNoChangeMessage(),
-          () => html`
-            <div class="whitespace-change-only-message">
-              This file only contains whitespace changes. Modify the whitespace
-              setting to see the changes.
-            </div>
-          `
-        )}
-      </div>
-    `;
-  }
-
-  private renderNewlineWarning() {
-    const newlineWarning = this.computeNewlineWarning();
-    if (!newlineWarning) return nothing;
-    return html`<div class="newlineWarning">${newlineWarning}</div>`;
-  }
-
-  private renderLoadingError() {
-    if (!this.errorMessage) return nothing;
-    return html`<div id="loadingError">${this.errorMessage}</div>`;
-  }
-
-  private renderSizeWarning() {
-    if (!this.showWarning) return nothing;
-    // TODO: Update comment about 'Whole file' as it's not in settings.
-    return html`
-      <div id="sizeWarning">
-        <p>
-          Prevented render because "Whole file" is enabled and this diff is very
-          large (about ${this.diffLength} lines).
-        </p>
-        <gr-button @click=${this.collapseContext}>
-          Render with limited context
-        </gr-button>
-        <gr-button @click=${this.handleFullBypass}>
-          Render anyway (may be slow)
-        </gr-button>
-      </div>
-    `;
-  }
-
-  private addSelectionListeners() {
-    document.addEventListener('selectionchange', this.handleSelectionChange);
-    document.addEventListener('mouseup', this.handleMouseUp);
-  }
-
-  private removeSelectionListeners() {
-    document.removeEventListener('selectionchange', this.handleSelectionChange);
-    document.removeEventListener('mouseup', this.handleMouseUp);
-  }
-
-  getLineNumEls(side: Side): HTMLElement[] {
-    return this.diffBuilder.getLineNumEls(side);
-  }
-
-  // Private but used in tests.
-  showNoChangeMessage() {
-    return (
-      !this.loading &&
-      this.diff &&
-      !this.diff.binary &&
-      this.prefs &&
-      this.prefs.ignore_whitespace !== 'IGNORE_NONE' &&
-      this.diffLength === 0
-    );
-  }
-
-  private readonly handleSelectionChange = () => {
-    // Because of shadow DOM selections, we handle the selectionchange here,
-    // and pass the shadow DOM selection into gr-diff-highlight, where the
-    // corresponding range is determined and normalized.
-    const selection = this.getShadowOrDocumentSelection();
-    this.highlights.handleSelectionChange(selection, false);
-  };
-
-  private readonly handleMouseUp = () => {
-    // To handle double-click outside of text creating comments, we check on
-    // mouse-up if there's a selection that just covers a line change. We
-    // can't do that on selection change since the user may still be dragging.
-    const selection = this.getShadowOrDocumentSelection();
-    this.highlights.handleSelectionChange(selection, true);
-  };
-
-  /** Gets the current selection, preferring the shadow DOM selection. */
-  private getShadowOrDocumentSelection() {
-    // When using native shadow DOM, the selection returned by
-    // document.getSelection() cannot reference the actual DOM elements making
-    // up the diff in Safari because they are in the shadow DOM of the gr-diff
-    // element. This takes the shadow DOM selection if one exists.
-    return this.shadowRoot?.getSelection
-      ? this.shadowRoot.getSelection()
-      : isSafari()
-      ? getContentEditableRange()
-      : document.getSelection();
-  }
-
-  private updateRanges(
-    addedThreadEls: GrDiffThreadElement[],
-    removedThreadEls: GrDiffThreadElement[]
-  ) {
-    function commentRangeFromThreadEl(
-      threadEl: GrDiffThreadElement
-    ): CommentRangeLayer | undefined {
-      const side = getSide(threadEl);
-      if (!side) return undefined;
-      const range = getRange(threadEl);
-      if (!range) return undefined;
-
-      return {side, range, id: threadEl.rootId};
-    }
-
-    // TODO(brohlfs): Rewrite `.map().filter() as ...` with `.reduce()` instead.
-    const addedCommentRanges = addedThreadEls
-      .map(commentRangeFromThreadEl)
-      .filter(range => !!range) as CommentRangeLayer[];
-    const removedCommentRanges = removedThreadEls
-      .map(commentRangeFromThreadEl)
-      .filter(range => !!range) as CommentRangeLayer[];
-    for (const removedCommentRange of removedCommentRanges) {
-      const i = this.commentRanges.findIndex(
-        cr =>
-          cr.side === removedCommentRange.side &&
-          rangesEqual(cr.range, removedCommentRange.range)
-      );
-      this.commentRanges.splice(i, 1);
-    }
-
-    if (addedCommentRanges?.length) {
-      this.commentRanges.push(...addedCommentRanges);
-    }
-    if (this.highlightRange) {
-      this.commentRanges.push({
-        side: Side.RIGHT,
-        range: this.highlightRange,
-        id: 'highlightRange',
-      });
-    }
-
-    this.diffBuilder.updateCommentRanges(this.commentRanges);
-  }
-
-  /**
-   * The key locations based on the comments and line of interests,
-   * where lines should not be collapsed.
-   *
-   */
-  private computeKeyLocations() {
-    const keyLocations: KeyLocations = {left: {}, right: {}};
-    if (this.lineOfInterest) {
-      const side = this.lineOfInterest.side;
-      keyLocations[side][this.lineOfInterest.lineNum] = true;
-    }
-    const threadEls = [...this.childNodes].filter(isThreadEl);
-
-    for (const threadEl of threadEls) {
-      const side = getSide(threadEl);
-      if (!side) continue;
-      const lineNum = getLine(threadEl);
-      const commentRange = getRange(threadEl);
-      keyLocations[side][lineNum] = true;
-      // Add start_line as well if exists,
-      // the being and end of the range should not be collapsed.
-      if (commentRange?.start_line) {
-        keyLocations[side][commentRange.start_line] = true;
-      }
-    }
-    return keyLocations;
-  }
-
-  // Dispatch events that are handled by the gr-diff-highlight.
-  private redispatchHoverEvents(
-    hoverEl: HTMLElement,
-    threadEl: GrDiffThreadElement
-  ) {
-    hoverEl.addEventListener('mouseenter', () => {
-      const data = getDataFromCommentThreadEl(threadEl);
-      if (data) fire(threadEl, 'comment-thread-mouseenter', data);
-    });
-    hoverEl.addEventListener('mouseleave', () => {
-      const data = getDataFromCommentThreadEl(threadEl);
-      if (data) fire(threadEl, 'comment-thread-mouseleave', data);
-    });
-  }
-
-  /** Cancel any remaining diff builder rendering work. */
-  cancel() {
-    this.diffBuilder.cleanup();
-    this.renderDiffTableTask?.cancel();
-  }
-
-  getCursorStops(): Array<HTMLElement | AbortStop> {
-    if (this.hidden && this.noAutoRender) return [];
-
-    // Get rendered stops.
-    const stops: Array<HTMLElement | AbortStop> =
-      this.diffBuilder.getLineNumberRows();
-
-    // If we are still loading this diff, abort after the rendered stops to
-    // avoid skipping over to e.g. the next file.
-    if (this.loading) {
-      stops.push(new AbortStop());
-    }
-    return stops;
-  }
-
-  isRangeSelected() {
-    return !!this.highlights.selectedRange;
-  }
-
-  toggleLeftDiff() {
-    toggleClass(this, 'no-left');
-  }
-
-  private blameChanged() {
-    this.diffBuilder.setBlame(this.blame);
-    if (this.blame) {
-      this.classList.add('showBlame');
-    } else {
-      this.classList.remove('showBlame');
-    }
-  }
-
-  // Private but used in tests.
-  handleTap(e: Event) {
-    const el = e.target as Element;
-
-    if (
-      el.getAttribute('data-value') !== LOST &&
-      (el.classList.contains('lineNum') ||
-        el.classList.contains('lineNumButton'))
-    ) {
-      this.addDraftAtLine(el);
-    } else if (
-      el.tagName === 'HL' ||
-      el.classList.contains('content') ||
-      el.classList.contains('contentText')
-    ) {
-      const target = getLineElByChild(el);
-      if (target) {
-        this.selectLine(target);
-      }
-    }
-  }
-
-  // Private but used in tests.
-  selectLine(el: Element) {
-    const lineNumber = Number(el.getAttribute('data-value'));
-    const side = el.classList.contains('left') ? Side.LEFT : Side.RIGHT;
-    this.dispatchSelectedLine(lineNumber, side);
-  }
-
-  private dispatchSelectedLine(number: LineNumber, side: Side) {
-    fire(this, 'line-selected', {
-      number,
-      side,
-      path: this.path,
-    });
-  }
-
-  addDraftAtLine(el: Element) {
-    this.selectLine(el);
-
-    const lineNum = getLineNumber(el);
-    if (lineNum === null) {
-      fireAlert(this, 'Invalid line number');
-      return;
-    }
-
-    this.createComment(el, lineNum);
-  }
-
-  createRangeComment() {
-    if (!this.isRangeSelected()) {
-      throw Error('Selection is needed for new range comment');
-    }
-    const selectedRange = this.highlights.selectedRange;
-    if (!selectedRange) throw Error('selected range not set');
-    const {side, range} = selectedRange;
-    this.createCommentForSelection(side, range);
-  }
-
-  createCommentForSelection(side: Side, range: CommentRange) {
-    const lineNum = range.end_line;
-    const lineEl = this.diffBuilder.getLineElByNumber(lineNum, side);
-    if (lineEl) {
-      this.createComment(lineEl, lineNum, side, range);
-    }
-  }
-
-  private handleCreateRangeComment(
-    e: CustomEvent<CreateRangeCommentEventDetail>
-  ) {
-    const range = e.detail.range;
-    const side = e.detail.side;
-    this.createCommentForSelection(side, range);
-  }
-
-  // Private but used in tests.
-  createComment(
-    lineEl: Element,
-    lineNum: LineNumber,
-    side?: Side,
-    range?: CommentRange
-  ) {
-    const contentEl = this.diffBuilder.getContentTdByLineEl(lineEl);
-    if (!contentEl) throw new Error('content el not found for line el');
-    side = side ?? this.getCommentSideByLineAndContent(lineEl, contentEl);
-    fire(this, 'create-comment', {
-      side,
-      lineNum,
-      range,
-    });
-  }
-
-  private getCommentSideByLineAndContent(
-    lineEl: Element,
-    contentEl: Element
-  ): Side {
-    return lineEl.classList.contains(Side.LEFT) ||
-      contentEl.classList.contains('remove')
-      ? Side.LEFT
-      : Side.RIGHT;
-  }
-
-  private lineOfInterestChanged() {
-    if (this.loading) return;
-    if (!this.lineOfInterest) return;
-    const lineNum = this.lineOfInterest.lineNum;
-    if (typeof lineNum !== 'number') return;
-    this.diffBuilder.unhideLine(lineNum, this.lineOfInterest.side);
-  }
-
-  private cleanup() {
-    this.cancel();
-    this.blame = null;
-    this.safetyBypass = null;
-    this.showWarning = false;
-    this.clearDiffContent();
-  }
-
-  private prefsChanged() {
-    if (!this.prefs) return;
-    this.diffModel.updateState({diffPrefs: this.prefs});
-
-    this.blame = null;
-    this.updatePreferenceStyles();
-
-    if (this.diff && !this.noRenderOnPrefsChange) {
-      this.debounceRenderDiffTable();
-    }
-  }
-
-  private updatePreferenceStyles() {
-    assertIsDefined(this.prefs, 'prefs');
-    const lineLength =
-      this.path === COMMIT_MSG_PATH
-        ? COMMIT_MSG_LINE_LENGTH
-        : this.prefs.line_length;
-    const sideBySide = this.viewMode === 'SIDE_BY_SIDE';
-
-    const responsiveMode = getResponsiveMode(this.prefs, this.renderPrefs);
-    const responsive = isResponsive(responsiveMode);
-    this.diffTableClass = responsive ? 'responsive' : '';
-    const lineLimit = `${lineLength}ch`;
-    this.style.setProperty(
-      '--line-limit-marker',
-      responsiveMode === 'FULL_RESPONSIVE' ? lineLimit : '-1px'
-    );
-    this.style.setProperty('--content-width', responsive ? 'none' : lineLimit);
-    if (responsiveMode === 'SHRINK_ONLY') {
-      // Calculating ideal (initial) width for the whole table including
-      // width of each table column (content and line number columns) and
-      // border. We also add a 1px correction as some values are calculated
-      // in 'ch'.
-
-      // We might have 1 to 2 columns for content depending if side-by-side
-      // or unified mode
-      const contentWidth = `${sideBySide ? 2 : 1} * ${lineLimit}`;
-
-      // We always have 2 columns for line number
-      const lineNumberWidth = `2 * ${getLineNumberCellWidth(this.prefs)}px`;
-
-      // border-right in ".section" css definition (in gr-diff_html.ts)
-      const sectionRightBorder = '1px';
-
-      // each sign col has 1ch width.
-      const signColsWidth =
-        sideBySide && this.renderPrefs?.show_sign_col ? '2ch' : '0ch';
-
-      // As some of these calculations are done using 'ch' we end up having <1px
-      // difference between ideal and calculated size for each side leading to
-      // lines using the max columns (e.g. 80) to wrap (decided exclusively by
-      // the browser).This happens even in monospace fonts. Empirically adding
-      // 2px as correction to be sure wrapping won't happen in these cases so it
-      // doesn't block further experimentation with the SHRINK_MODE. This was
-      // previously set to 1px but due to to a more aggressive text wrapping
-      // (via word-break: break-all; - check .contextText) we need to be even
-      // more lenient in some cases. If we find another way to avoid this
-      // correction we will change it.
-      const dontWrapCorrection = '2px';
-      this.style.setProperty(
-        '--diff-max-width',
-        `calc(${contentWidth} + ${lineNumberWidth} + ${signColsWidth} + ${sectionRightBorder} + ${dontWrapCorrection})`
-      );
-    } else {
-      this.style.setProperty('--diff-max-width', 'none');
-    }
-    if (this.prefs.font_size) {
-      this.style.setProperty('--font-size', `${this.prefs.font_size}px`);
-    }
-  }
-
-  private renderPrefsChanged() {
-    this.diffModel.updateState({renderPrefs: this.renderPrefs});
-    if (this.renderPrefs.hide_left_side) {
-      this.classList.add('no-left');
-    }
-    if (this.renderPrefs.disable_context_control_buttons) {
-      this.classList.add('disable-context-control-buttons');
-    }
-    if (this.renderPrefs.hide_line_length_indicator) {
-      this.classList.add('hide-line-length-indicator');
-    }
-    if (this.renderPrefs.show_sign_col) {
-      this.classList.add('with-sign-col');
-    }
-    if (this.prefs) {
-      this.updatePreferenceStyles();
-    }
-    this.diffBuilder.updateRenderPrefs(this.renderPrefs);
-  }
-
-  private diffChanged() {
-    this.loading = true;
-    this.cleanup();
-    if (this.diff) {
-      this.diffLength = this.getDiffLength(this.diff);
-      this.debounceRenderDiffTable();
-      assertIsDefined(this.diffTable, 'diffTable');
-      this.diffSelection.init(this.diff, this.diffTable);
-      this.highlights.init(this.diffTable, this.diffBuilder);
-    }
-  }
-
-  // Implemented so the test can stub it.
-  getDiffLength(diff?: DiffInfo) {
-    return getDiffLength(diff);
-  }
-
-  /**
-   * When called multiple times from the same task, will call
-   * _renderDiffTable only once, in the next task (scheduled via `setTimeout`).
-   *
-   * This should be used instead of calling _renderDiffTable directly to
-   * render the diff in response to an input change, because there may be
-   * multiple inputs changing in the same microtask, but we only want to
-   * render once.
-   */
-  private debounceRenderDiffTable() {
-    // at this point gr-diff might be considered as rendered from the outside
-    // (client), although it was not actually rendered. Clients need to know
-    // when it is safe to perform operations like cursor moves, for example,
-    // and if changing an input actually requires a reload of the diff table.
-    // Since `fire` is synchronous it allows clients to be aware when an
-    // async render is needed and that they can wait for a further `render`
-    // event to actually take further action.
-    fire(this, 'render-required', {});
-    this.renderDiffTableTask = debounceP(
-      this.renderDiffTableTask,
-      async () => await this.renderDiffTable()
-    );
-    this.renderDiffTableTask.catch((e: unknown) => {
-      if (e === DELAYED_CANCELLATION) return;
-      throw e;
-    });
-  }
-
-  // Private but used in tests.
-  async renderDiffTable() {
-    this.unobserveNodes();
-    if (!this.diff || !this.prefs) {
-      fire(this, 'render', {});
-      return;
-    }
-    if (
-      this.prefs.context === -1 &&
-      this.diffLength &&
-      this.diffLength >= LARGE_DIFF_THRESHOLD_LINES &&
-      this.safetyBypass === null
-    ) {
-      this.showWarning = true;
-      fire(this, 'render', {});
-      return;
-    }
-
-    this.showWarning = false;
-
-    const keyLocations = this.computeKeyLocations();
-
-    this.diffModel.setState({
-      diff: this.diff,
-      path: this.path,
-      renderPrefs: this.renderPrefs,
-      diffPrefs: this.prefs,
-    });
-
-    // TODO: Setting tons of public properties like this is obviously a code
-    // smell. We are introducing a diff model for managing all this
-    // data. Then diff builder will only need access to that model.
-    this.diffBuilder.prefs = this.getBypassPrefs();
-    this.diffBuilder.renderPrefs = this.renderPrefs;
-    this.diffBuilder.diff = this.diff;
-    this.diffBuilder.path = this.path;
-    this.diffBuilder.viewMode = this.viewMode;
-    this.diffBuilder.layers = this.layers ?? [];
-    this.diffBuilder.baseImage = this.baseImage ?? null;
-    this.diffBuilder.revisionImage = this.revisionImage ?? null;
-    this.diffBuilder.useNewImageDiffUi = this.useNewImageDiffUi;
-    this.diffBuilder.diffElement = this.diffTable;
-    // `this.commentRanges` are probably empty here, because they will only be
-    // populated by the node observer, which starts observing *after* rendering.
-    this.diffBuilder.updateCommentRanges(this.commentRanges);
-    this.diffBuilder.updateCoverageRanges(this.coverageRanges);
-    await this.diffBuilder.render(keyLocations);
-  }
-
-  private handleRenderContent() {
-    this.querySelectorAll('gr-ranged-comment-hint').forEach(element =>
-      element.remove()
-    );
-    this.loading = false;
-    this.observeNodes();
-    // We are just converting 'render-content' into 'render' here. Maybe we
-    // should retire the 'render' event in favor of 'render-content'?
-    fire(this, 'render', {});
-  }
-
-  private observeNodes() {
-    // First stop observing old nodes.
-    this.unobserveNodes();
-    // Then introduce a Mutation observer that watches for children being added
-    // to gr-diff. If those children are `isThreadEl`, namely then they are
-    // processed.
-    this.nodeObserver = new MutationObserver(mutations => {
-      const addedThreadEls = extractAddedNodes(mutations).filter(isThreadEl);
-      const removedThreadEls =
-        extractRemovedNodes(mutations).filter(isThreadEl);
-      this.processNodes(addedThreadEls, removedThreadEls);
-    });
-    this.nodeObserver.observe(this, {childList: true});
-    // Make sure to process existing gr-comment-threads that already exist.
-    this.processNodes([...this.childNodes].filter(isThreadEl), []);
-  }
-
-  private processNodes(
-    addedThreadEls: GrDiffThreadElement[],
-    removedThreadEls: GrDiffThreadElement[]
-  ) {
-    this.updateRanges(addedThreadEls, removedThreadEls);
-    addedThreadEls.forEach(threadEl =>
-      this.redispatchHoverEvents(threadEl, threadEl)
-    );
-    // Removed nodes do not need to be handled because all this code does is
-    // adding a slot for the added thread elements, and the extra slots do
-    // not hurt. It's probably a bigger performance cost to remove them than
-    // to keep them around. Medium term we can even consider to add one slot
-    // for each line from the start.
-    for (const threadEl of addedThreadEls) {
-      const lineNum = getLine(threadEl);
-      const commentSide = getSide(threadEl);
-      const range = getRange(threadEl);
-      if (!commentSide) continue;
-      const lineEl = this.diffBuilder.getLineElByNumber(lineNum, commentSide);
-      // When the line the comment refers to does not exist, log an error
-      // but don't crash. This can happen e.g. if the API does not fully
-      // validate e.g. (robot) comments
-      if (!lineEl) {
-        console.error(
-          'thread attached to line ',
-          commentSide,
-          lineNum,
-          ' which does not exist.'
-        );
-        continue;
-      }
-      const contentEl = this.diffBuilder.getContentTdByLineEl(lineEl);
-      if (!contentEl) continue;
-      if (lineNum === LOST) {
-        this.insertPortedCommentsWithoutRangeMessage(contentEl);
-      }
-
-      const slotAtt = threadEl.getAttribute('slot');
-      if (range && isLongCommentRange(range) && slotAtt) {
-        const longRangeCommentHint = document.createElement(
-          'gr-ranged-comment-hint'
-        );
-        longRangeCommentHint.range = range;
-        longRangeCommentHint.setAttribute('threadElRootId', threadEl.rootId);
-        longRangeCommentHint.setAttribute('slot', slotAtt);
-        this.insertBefore(longRangeCommentHint, threadEl);
-        this.redispatchHoverEvents(longRangeCommentHint, threadEl);
-      }
-    }
-
-    for (const threadEl of removedThreadEls) {
-      this.querySelector(
-        `gr-ranged-comment-hint[threadElRootId="${threadEl.rootId}"]`
-      )?.remove();
-    }
-  }
-
-  private unobserveNodes() {
-    if (this.nodeObserver) {
-      this.nodeObserver.disconnect();
-      this.nodeObserver = undefined;
-    }
-    // You only stop observing for comment thread elements when the diff is
-    // completely rendered from scratch. And then comment thread elements
-    // will be (re-)added *after* rendering is done. That is also when we
-    // re-start observing. So it is appropriate to thoroughly clean up
-    // everything that the observer is managing.
-    this.commentRanges = [];
-  }
-
-  private insertPortedCommentsWithoutRangeMessage(lostCell: Element) {
-    const existingMessage = lostCell.querySelector('div.lost-message');
-    if (existingMessage) return;
-
-    const div = document.createElement('div');
-    div.className = 'lost-message';
-    const icon = document.createElement('gr-icon');
-    icon.setAttribute('icon', 'info');
-    div.appendChild(icon);
-    const span = document.createElement('span');
-    span.innerText = 'Original comment position not found in this patchset';
-    div.appendChild(span);
-    lostCell.insertBefore(div, lostCell.firstChild);
-  }
-
-  /**
-   * Get the preferences object including the safety bypass context (if any).
-   */
-  private getBypassPrefs() {
-    assertIsDefined(this.prefs, 'prefs');
-    if (this.safetyBypass !== null) {
-      return {...this.prefs, context: this.safetyBypass};
-    }
-    return this.prefs;
-  }
-
-  clearDiffContent() {
-    this.unobserveNodes();
-    if (!this.diffTable) return;
-    while (this.diffTable.hasChildNodes()) {
-      this.diffTable.removeChild(this.diffTable.lastChild!);
-    }
-  }
-
-  // Private but used in tests.
-  computeDiffHeaderItems() {
-    return (this.diff?.diff_header ?? [])
-      .filter(
-        item =>
-          !(
-            item.startsWith('diff --git ') ||
-            item.startsWith('index ') ||
-            item.startsWith('+++ ') ||
-            item.startsWith('--- ') ||
-            item === 'Binary files differ'
-          )
-      )
-      .map(expandFileMode);
-  }
-
-  private handleFullBypass() {
-    this.safetyBypass = FULL_CONTEXT;
-    this.debounceRenderDiffTable();
-  }
-
-  private collapseContext() {
-    // Uses the default context amount if the preference is for the entire file.
-    this.safetyBypass =
-      this.prefs?.context && this.prefs.context >= 0
-        ? null
-        : createDefaultDiffPrefs().context;
-    this.debounceRenderDiffTable();
-  }
-
-  toggleAllContext() {
-    if (!this.prefs) {
-      return;
-    }
-    if (this.getBypassPrefs().context < 0) {
-      this.collapseContext();
-    } else {
-      this.handleFullBypass();
-    }
-  }
-
-  private computeNewlineWarning(): string | undefined {
-    const messages = [];
-    if (this.showNewlineWarningLeft) {
-      messages.push(NO_NEWLINE_LEFT);
-    }
-    if (this.showNewlineWarningRight) {
-      messages.push(NO_NEWLINE_RIGHT);
-    }
-    if (!messages.length) {
-      return undefined;
-    }
-    return messages.join(' \u2014 '); // \u2014 - '—'
-  }
-}
-
-function extractAddedNodes(mutations: MutationRecord[]) {
-  return mutations.flatMap(mutation => [...mutation.addedNodes]);
-}
-
-function extractRemovedNodes(mutations: MutationRecord[]) {
-  return mutations.flatMap(mutation => [...mutation.removedNodes]);
-}
-
-if (!isNewDiff()) {
-  customElements.define('gr-diff', GrDiff);
-}
-
-declare global {
-  interface HTMLElementTagNameMap {
-    'gr-diff': LitElement;
-  }
-  interface HTMLElementEventMap {
-    'comment-thread-mouseenter': CustomEvent<GrDiffCommentThread>;
-    'comment-thread-mouseleave': CustomEvent<GrDiffCommentThread>;
-    'loading-changed': ValueChangedEvent<boolean>;
-    'render-required': CustomEvent<{}>;
-  }
-}
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff_test.ts b/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff_test.ts
deleted file mode 100644
index ac444b7..0000000
--- a/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff_test.ts
+++ /dev/null
@@ -1,4183 +0,0 @@
-/**
- * @license
- * Copyright 2015 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import '../../../test/common-test-setup';
-import {createDiff} from '../../../test/test-data-generators';
-import './gr-diff';
-import {getComputedStyleValue} from '../../../utils/dom-util';
-import '@polymer/paper-button/paper-button';
-import {
-  DiffContent,
-  DiffInfo,
-  DiffPreferencesInfo,
-  DiffViewMode,
-  IgnoreWhitespaceType,
-  Side,
-} from '../../../api/diff';
-import {
-  mockPromise,
-  mouseDown,
-  query,
-  queryAll,
-  queryAndAssert,
-  waitEventLoop,
-  waitQueryAndAssert,
-  waitUntil,
-} from '../../../test/test-utils';
-import {AbortStop} from '../../../api/core';
-import {waitForEventOnce} from '../../../utils/event-util';
-import {GrDiff} from './gr-diff';
-import {ImageInfo} from '../../../types/common';
-import {GrRangedCommentHint} from '../../diff/gr-ranged-comment-hint/gr-ranged-comment-hint';
-import {assertIsDefined} from '../../../utils/common-util';
-import {fixture, html, assert} from '@open-wc/testing';
-
-suite('gr-diff a11y test', () => {
-  test('audit', async () => {
-    assert.isAccessible(await fixture(html`<gr-diff></gr-diff>`));
-  });
-});
-
-suite('gr-diff tests', () => {
-  let element: GrDiff;
-
-  const MINIMAL_PREFS: DiffPreferencesInfo = {
-    tab_size: 2,
-    line_length: 80,
-    font_size: 12,
-    context: 3,
-    ignore_whitespace: 'IGNORE_NONE',
-  };
-
-  setup(async () => {
-    element = await fixture<GrDiff>(html`<gr-diff></gr-diff>`);
-  });
-
-  suite('rendering', () => {
-    test('empty diff', async () => {
-      await element.updateComplete;
-      assert.shadowDom.equal(
-        element,
-        /* HTML */ `
-          <div class="diffContainer oldDiff sideBySide">
-            <table id="diffTable"></table>
-          </div>
-        `
-      );
-    });
-
-    test('a unified diff lit', async () => {
-      element.viewMode = DiffViewMode.UNIFIED;
-      element.prefs = {...MINIMAL_PREFS};
-      element.diff = createDiff();
-      await element.updateComplete;
-      await waitForEventOnce(element, 'render');
-      assert.shadowDom.equal(
-        element,
-        /* HTML */ `
-          <div class="diffContainer oldDiff unified">
-            <table class="selected-right" id="diffTable">
-              <colgroup>
-                <col class="blame gr-diff" />
-                <col class="gr-diff" width="48" />
-                <col class="gr-diff" width="48" />
-                <col class="gr-diff" />
-              </colgroup>
-              <tbody class="both gr-diff section">
-                <tr
-                  aria-labelledby="left-button-LOST right-button-LOST right-content-LOST"
-                  class="both diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="LOST"></td>
-                  <td class="gr-diff left lineNum" data-value="LOST"></td>
-                  <td class="gr-diff lineNum right" data-value="LOST"></td>
-                  <td class="both content gr-diff lost no-intraline-info right">
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-              </tbody>
-              <tbody class="both gr-diff section">
-                <tr
-                  aria-labelledby="left-button-FILE right-button-FILE right-content-FILE"
-                  class="both diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="FILE"></td>
-                  <td class="gr-diff left lineNum" data-value="FILE">
-                    <button
-                      aria-label="Add file comment"
-                      class="gr-diff left lineNumButton"
-                      data-value="FILE"
-                      id="left-button-FILE"
-                      tabindex="-1"
-                    >
-                      File
-                    </button>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="FILE">
-                    <button
-                      aria-label="Add file comment"
-                      class="gr-diff lineNumButton right"
-                      data-value="FILE"
-                      id="right-button-FILE"
-                      tabindex="-1"
-                    >
-                      File
-                    </button>
-                  </td>
-                  <td class="both content file gr-diff no-intraline-info right">
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-              </tbody>
-              <tbody class="both gr-diff section">
-                <tr
-                  aria-labelledby="left-button-1 right-button-1 right-content-1"
-                  class="both diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="1"></td>
-                  <td class="gr-diff left lineNum" data-value="1">
-                    <button
-                      aria-label="1 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="1"
-                      id="left-button-1"
-                      tabindex="-1"
-                    >
-                      1
-                    </button>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="1">
-                    <button
-                      aria-label="1 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="1"
-                      id="right-button-1"
-                      tabindex="-1"
-                    >
-                      1
-                    </button>
-                  </td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-1"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-2 right-button-2 right-content-2"
-                  class="both diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="2"></td>
-                  <td class="gr-diff left lineNum" data-value="2">
-                    <button
-                      aria-label="2 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="2"
-                      id="left-button-2"
-                      tabindex="-1"
-                    >
-                      2
-                    </button>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="2">
-                    <button
-                      aria-label="2 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="2"
-                      id="right-button-2"
-                      tabindex="-1"
-                    >
-                      2
-                    </button>
-                  </td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-2"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-3 right-button-3 right-content-3"
-                  class="both diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="3"></td>
-                  <td class="gr-diff left lineNum" data-value="3">
-                    <button
-                      aria-label="3 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="3"
-                      id="left-button-3"
-                      tabindex="-1"
-                    >
-                      3
-                    </button>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="3">
-                    <button
-                      aria-label="3 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="3"
-                      id="right-button-3"
-                      tabindex="-1"
-                    >
-                      3
-                    </button>
-                  </td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-3"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-4 right-button-4 right-content-4"
-                  class="both diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="4"></td>
-                  <td class="gr-diff left lineNum" data-value="4">
-                    <button
-                      aria-label="4 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="4"
-                      id="left-button-4"
-                      tabindex="-1"
-                    >
-                      4
-                    </button>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="4">
-                    <button
-                      aria-label="4 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="4"
-                      id="right-button-4"
-                      tabindex="-1"
-                    >
-                      4
-                    </button>
-                  </td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-4"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-              </tbody>
-              <tbody class="delta gr-diff section total">
-                <tr
-                  aria-labelledby="right-button-5 right-content-5"
-                  class="add diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="0"></td>
-                  <td class="gr-diff left"></td>
-                  <td class="gr-diff lineNum right" data-value="5">
-                    <button
-                      aria-label="5 added"
-                      class="gr-diff lineNumButton right"
-                      data-value="5"
-                      id="right-button-5"
-                      tabindex="-1"
-                    >
-                      5
-                    </button>
-                  </td>
-                  <td class="add content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-5"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="right-button-6 right-content-6"
-                  class="add diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="0"></td>
-                  <td class="gr-diff left"></td>
-                  <td class="gr-diff lineNum right" data-value="6">
-                    <button
-                      aria-label="6 added"
-                      class="gr-diff lineNumButton right"
-                      data-value="6"
-                      id="right-button-6"
-                      tabindex="-1"
-                    >
-                      6
-                    </button>
-                  </td>
-                  <td class="add content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-6"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="right-button-7 right-content-7"
-                  class="add diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="0"></td>
-                  <td class="gr-diff left"></td>
-                  <td class="gr-diff lineNum right" data-value="7">
-                    <button
-                      aria-label="7 added"
-                      class="gr-diff lineNumButton right"
-                      data-value="7"
-                      id="right-button-7"
-                      tabindex="-1"
-                    >
-                      7
-                    </button>
-                  </td>
-                  <td class="add content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-7"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-              </tbody>
-              <tbody class="both gr-diff section">
-                <tr
-                  aria-labelledby="left-button-5 right-button-8 right-content-8"
-                  class="both diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="5"></td>
-                  <td class="gr-diff left lineNum" data-value="5">
-                    <button
-                      aria-label="5 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="5"
-                      id="left-button-5"
-                      tabindex="-1"
-                    >
-                      5
-                    </button>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="8">
-                    <button
-                      aria-label="8 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="8"
-                      id="right-button-8"
-                      tabindex="-1"
-                    >
-                      8
-                    </button>
-                  </td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-8"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-6 right-button-9 right-content-9"
-                  class="both diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="6"></td>
-                  <td class="gr-diff left lineNum" data-value="6">
-                    <button
-                      aria-label="6 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="6"
-                      id="left-button-6"
-                      tabindex="-1"
-                    >
-                      6
-                    </button>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="9">
-                    <button
-                      aria-label="9 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="9"
-                      id="right-button-9"
-                      tabindex="-1"
-                    >
-                      9
-                    </button>
-                  </td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-9"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-7 right-button-10 right-content-10"
-                  class="both diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="7"></td>
-                  <td class="gr-diff left lineNum" data-value="7">
-                    <button
-                      aria-label="7 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="7"
-                      id="left-button-7"
-                      tabindex="-1"
-                    >
-                      7
-                    </button>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="10">
-                    <button
-                      aria-label="10 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="10"
-                      id="right-button-10"
-                      tabindex="-1"
-                    >
-                      10
-                    </button>
-                  </td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-10"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-8 right-button-11 right-content-11"
-                  class="both diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="8"></td>
-                  <td class="gr-diff left lineNum" data-value="8">
-                    <button
-                      aria-label="8 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="8"
-                      id="left-button-8"
-                      tabindex="-1"
-                    >
-                      8
-                    </button>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="11">
-                    <button
-                      aria-label="11 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="11"
-                      id="right-button-11"
-                      tabindex="-1"
-                    >
-                      11
-                    </button>
-                  </td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-11"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-9 right-button-12 right-content-12"
-                  class="both diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="9"></td>
-                  <td class="gr-diff left lineNum" data-value="9">
-                    <button
-                      aria-label="9 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="9"
-                      id="left-button-9"
-                      tabindex="-1"
-                    >
-                      9
-                    </button>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="12">
-                    <button
-                      aria-label="12 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="12"
-                      id="right-button-12"
-                      tabindex="-1"
-                    >
-                      12
-                    </button>
-                  </td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-12"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-              </tbody>
-              <tbody class="delta gr-diff section total">
-                <tr
-                  aria-labelledby="left-button-10 left-content-10"
-                  class="diff-row gr-diff remove unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="10"></td>
-                  <td class="gr-diff left lineNum" data-value="10">
-                    <button
-                      aria-label="10 removed"
-                      class="gr-diff left lineNumButton"
-                      data-value="10"
-                      id="left-button-10"
-                      tabindex="-1"
-                    >
-                      10
-                    </button>
-                  </td>
-                  <td class="gr-diff right"></td>
-                  <td class="content gr-diff left no-intraline-info remove">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-10"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-11 left-content-11"
-                  class="diff-row gr-diff remove unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="11"></td>
-                  <td class="gr-diff left lineNum" data-value="11">
-                    <button
-                      aria-label="11 removed"
-                      class="gr-diff left lineNumButton"
-                      data-value="11"
-                      id="left-button-11"
-                      tabindex="-1"
-                    >
-                      11
-                    </button>
-                  </td>
-                  <td class="gr-diff right"></td>
-                  <td class="content gr-diff left no-intraline-info remove">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-11"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-12 left-content-12"
-                  class="diff-row gr-diff remove unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="12"></td>
-                  <td class="gr-diff left lineNum" data-value="12">
-                    <button
-                      aria-label="12 removed"
-                      class="gr-diff left lineNumButton"
-                      data-value="12"
-                      id="left-button-12"
-                      tabindex="-1"
-                    >
-                      12
-                    </button>
-                  </td>
-                  <td class="gr-diff right"></td>
-                  <td class="content gr-diff left no-intraline-info remove">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-12"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-13 left-content-13"
-                  class="diff-row gr-diff remove unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="13"></td>
-                  <td class="gr-diff left lineNum" data-value="13">
-                    <button
-                      aria-label="13 removed"
-                      class="gr-diff left lineNumButton"
-                      data-value="13"
-                      id="left-button-13"
-                      tabindex="-1"
-                    >
-                      13
-                    </button>
-                  </td>
-                  <td class="gr-diff right"></td>
-                  <td class="content gr-diff left no-intraline-info remove">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-13"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                </tr>
-              </tbody>
-              <tbody class="delta gr-diff ignoredWhitespaceOnly section">
-                <tr
-                  aria-labelledby="right-button-13 right-content-13"
-                  class="add diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="0"></td>
-                  <td class="gr-diff left"></td>
-                  <td class="gr-diff lineNum right" data-value="13">
-                    <button
-                      aria-label="13 added"
-                      class="gr-diff lineNumButton right"
-                      data-value="13"
-                      id="right-button-13"
-                      tabindex="-1"
-                    >
-                      13
-                    </button>
-                  </td>
-                  <td class="add content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-13"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="right-button-14 right-content-14"
-                  class="add diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="0"></td>
-                  <td class="gr-diff left"></td>
-                  <td class="gr-diff lineNum right" data-value="14">
-                    <button
-                      aria-label="14 added"
-                      class="gr-diff lineNumButton right"
-                      data-value="14"
-                      id="right-button-14"
-                      tabindex="-1"
-                    >
-                      14
-                    </button>
-                  </td>
-                  <td class="add content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-14"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-              </tbody>
-              <tbody class="delta gr-diff section">
-                <tr
-                  aria-labelledby="left-button-16 left-content-16"
-                  class="diff-row gr-diff remove unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="16"></td>
-                  <td class="gr-diff left lineNum" data-value="16">
-                    <button
-                      aria-label="16 removed"
-                      class="gr-diff left lineNumButton"
-                      data-value="16"
-                      id="left-button-16"
-                      tabindex="-1"
-                    >
-                      16
-                    </button>
-                  </td>
-                  <td class="gr-diff right"></td>
-                  <td class="content gr-diff left remove">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-16"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="right-button-15 right-content-15"
-                  class="add diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="0"></td>
-                  <td class="gr-diff left"></td>
-                  <td class="gr-diff lineNum right" data-value="15">
-                    <button
-                      aria-label="15 added"
-                      class="gr-diff lineNumButton right"
-                      data-value="15"
-                      id="right-button-15"
-                      tabindex="-1"
-                    >
-                      15
-                    </button>
-                  </td>
-                  <td class="add content gr-diff right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-15"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-              </tbody>
-              <tbody class="both gr-diff section">
-                <tr
-                  aria-labelledby="left-button-17 right-button-16 right-content-16"
-                  class="both diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="17"></td>
-                  <td class="gr-diff left lineNum" data-value="17">
-                    <button
-                      aria-label="17 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="17"
-                      id="left-button-17"
-                      tabindex="-1"
-                    >
-                      17
-                    </button>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="16">
-                    <button
-                      aria-label="16 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="16"
-                      id="right-button-16"
-                      tabindex="-1"
-                    >
-                      16
-                    </button>
-                  </td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-16"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-18 right-button-17 right-content-17"
-                  class="both diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="18"></td>
-                  <td class="gr-diff left lineNum" data-value="18">
-                    <button
-                      aria-label="18 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="18"
-                      id="left-button-18"
-                      tabindex="-1"
-                    >
-                      18
-                    </button>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="17">
-                    <button
-                      aria-label="17 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="17"
-                      id="right-button-17"
-                      tabindex="-1"
-                    >
-                      17
-                    </button>
-                  </td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-17"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-19 right-button-18 right-content-18"
-                  class="both diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="19"></td>
-                  <td class="gr-diff left lineNum" data-value="19">
-                    <button
-                      aria-label="19 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="19"
-                      id="left-button-19"
-                      tabindex="-1"
-                    >
-                      19
-                    </button>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="18">
-                    <button
-                      aria-label="18 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="18"
-                      id="right-button-18"
-                      tabindex="-1"
-                    >
-                      18
-                    </button>
-                  </td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-18"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-              </tbody>
-              <tbody class="contextControl gr-diff section">
-                <tr class="above contextBackground gr-diff unified">
-                  <td class="blame gr-diff" data-line-number="0"></td>
-                  <td class="contextLineNum gr-diff"></td>
-                  <td class="contextLineNum gr-diff"></td>
-                  <td class="gr-diff"></td>
-                </tr>
-                <tr class="dividerRow gr-diff show-both">
-                  <td class="blame gr-diff" data-line-number="0"></td>
-                  <td class="dividerCell gr-diff" colspan="3">
-                    <gr-context-controls class="gr-diff" showconfig="both">
-                    </gr-context-controls>
-                  </td>
-                </tr>
-                <tr class="below contextBackground gr-diff unified">
-                  <td class="blame gr-diff" data-line-number="0"></td>
-                  <td class="contextLineNum gr-diff"></td>
-                  <td class="contextLineNum gr-diff"></td>
-                  <td class="gr-diff"></td>
-                </tr>
-              </tbody>
-              <tbody class="both gr-diff section">
-                <tr
-                  aria-labelledby="left-button-38 right-button-37 right-content-37"
-                  class="both diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="38"></td>
-                  <td class="gr-diff left lineNum" data-value="38">
-                    <button
-                      aria-label="38 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="38"
-                      id="left-button-38"
-                      tabindex="-1"
-                    >
-                      38
-                    </button>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="37">
-                    <button
-                      aria-label="37 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="37"
-                      id="right-button-37"
-                      tabindex="-1"
-                    >
-                      37
-                    </button>
-                  </td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-37"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-39 right-button-38 right-content-38"
-                  class="both diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="39"></td>
-                  <td class="gr-diff left lineNum" data-value="39">
-                    <button
-                      aria-label="39 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="39"
-                      id="left-button-39"
-                      tabindex="-1"
-                    >
-                      39
-                    </button>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="38">
-                    <button
-                      aria-label="38 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="38"
-                      id="right-button-38"
-                      tabindex="-1"
-                    >
-                      38
-                    </button>
-                  </td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-38"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-40 right-button-39 right-content-39"
-                  class="both diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="40"></td>
-                  <td class="gr-diff left lineNum" data-value="40">
-                    <button
-                      aria-label="40 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="40"
-                      id="left-button-40"
-                      tabindex="-1"
-                    >
-                      40
-                    </button>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="39">
-                    <button
-                      aria-label="39 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="39"
-                      id="right-button-39"
-                      tabindex="-1"
-                    >
-                      39
-                    </button>
-                  </td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-39"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-              </tbody>
-              <tbody class="delta gr-diff section total">
-                <tr
-                  aria-labelledby="right-button-40 right-content-40"
-                  class="add diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="0"></td>
-                  <td class="gr-diff left"></td>
-                  <td class="gr-diff lineNum right" data-value="40">
-                    <button
-                      aria-label="40 added"
-                      class="gr-diff lineNumButton right"
-                      data-value="40"
-                      id="right-button-40"
-                      tabindex="-1"
-                    >
-                      40
-                    </button>
-                  </td>
-                  <td class="add content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-40"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="right-button-41 right-content-41"
-                  class="add diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="0"></td>
-                  <td class="gr-diff left"></td>
-                  <td class="gr-diff lineNum right" data-value="41">
-                    <button
-                      aria-label="41 added"
-                      class="gr-diff lineNumButton right"
-                      data-value="41"
-                      id="right-button-41"
-                      tabindex="-1"
-                    >
-                      41
-                    </button>
-                  </td>
-                  <td class="add content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-41"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="right-button-42 right-content-42"
-                  class="add diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="0"></td>
-                  <td class="gr-diff left"></td>
-                  <td class="gr-diff lineNum right" data-value="42">
-                    <button
-                      aria-label="42 added"
-                      class="gr-diff lineNumButton right"
-                      data-value="42"
-                      id="right-button-42"
-                      tabindex="-1"
-                    >
-                      42
-                    </button>
-                  </td>
-                  <td class="add content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-42"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="right-button-43 right-content-43"
-                  class="add diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="0"></td>
-                  <td class="gr-diff left"></td>
-                  <td class="gr-diff lineNum right" data-value="43">
-                    <button
-                      aria-label="43 added"
-                      class="gr-diff lineNumButton right"
-                      data-value="43"
-                      id="right-button-43"
-                      tabindex="-1"
-                    >
-                      43
-                    </button>
-                  </td>
-                  <td class="add content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-43"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-              </tbody>
-              <tbody class="both gr-diff section">
-                <tr
-                  aria-labelledby="left-button-41 right-button-44 right-content-44"
-                  class="both diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="41"></td>
-                  <td class="gr-diff left lineNum" data-value="41">
-                    <button
-                      aria-label="41 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="41"
-                      id="left-button-41"
-                      tabindex="-1"
-                    >
-                      41
-                    </button>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="44">
-                    <button
-                      aria-label="44 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="44"
-                      id="right-button-44"
-                      tabindex="-1"
-                    >
-                      44
-                    </button>
-                  </td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-44"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-42 right-button-45 right-content-45"
-                  class="both diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="42"></td>
-                  <td class="gr-diff left lineNum" data-value="42">
-                    <button
-                      aria-label="42 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="42"
-                      id="left-button-42"
-                      tabindex="-1"
-                    >
-                      42
-                    </button>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="45">
-                    <button
-                      aria-label="45 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="45"
-                      id="right-button-45"
-                      tabindex="-1"
-                    >
-                      45
-                    </button>
-                  </td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-45"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-43 right-button-46 right-content-46"
-                  class="both diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="43"></td>
-                  <td class="gr-diff left lineNum" data-value="43">
-                    <button
-                      aria-label="43 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="43"
-                      id="left-button-43"
-                      tabindex="-1"
-                    >
-                      43
-                    </button>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="46">
-                    <button
-                      aria-label="46 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="46"
-                      id="right-button-46"
-                      tabindex="-1"
-                    >
-                      46
-                    </button>
-                  </td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-46"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-44 right-button-47 right-content-47"
-                  class="both diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="44"></td>
-                  <td class="gr-diff left lineNum" data-value="44">
-                    <button
-                      aria-label="44 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="44"
-                      id="left-button-44"
-                      tabindex="-1"
-                    >
-                      44
-                    </button>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="47">
-                    <button
-                      aria-label="47 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="47"
-                      id="right-button-47"
-                      tabindex="-1"
-                    >
-                      47
-                    </button>
-                  </td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-47"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-45 right-button-48 right-content-48"
-                  class="both diff-row gr-diff unified"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="45"></td>
-                  <td class="gr-diff left lineNum" data-value="45">
-                    <button
-                      aria-label="45 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="45"
-                      id="left-button-45"
-                      tabindex="-1"
-                    >
-                      45
-                    </button>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="48">
-                    <button
-                      aria-label="48 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="48"
-                      id="right-button-48"
-                      tabindex="-1"
-                    >
-                      48
-                    </button>
-                  </td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-48"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-              </tbody>
-            </table>
-          </div>
-        `,
-        {
-          ignoreTags: [
-            'gr-context-controls-section',
-            'gr-diff-section',
-            'gr-diff-row',
-            'gr-diff-text',
-            'gr-legacy-text',
-            'slot',
-          ],
-        }
-      );
-    });
-
-    test('a normal diff lit', async () => {
-      element.prefs = {...MINIMAL_PREFS};
-      element.diff = createDiff();
-      await element.updateComplete;
-      await waitForEventOnce(element, 'render');
-      assert.shadowDom.equal(
-        element,
-        /* HTML */ `
-          <div class="diffContainer oldDiff sideBySide">
-            <table class="selected-right" id="diffTable">
-              <colgroup>
-                <col class="blame gr-diff" />
-                <col class="gr-diff left" width="48" />
-                <col class="gr-diff left sign" />
-                <col class="gr-diff left" />
-                <col class="gr-diff right" width="48" />
-                <col class="gr-diff right sign" />
-                <col class="gr-diff right" />
-              </colgroup>
-              <tbody class="both gr-diff section">
-                <tr
-                  aria-labelledby="left-button-LOST left-content-LOST right-button-LOST right-content-LOST"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="both"
-                  right-type="both"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="LOST"></td>
-                  <td class="gr-diff left lineNum" data-value="LOST"></td>
-                  <td class="gr-diff left no-intraline-info sign"></td>
-                  <td class="both content gr-diff left lost no-intraline-info">
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="LOST"></td>
-                  <td class="gr-diff no-intraline-info right sign"></td>
-                  <td class="both content gr-diff lost no-intraline-info right">
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-              </tbody>
-              <tbody class="both gr-diff section">
-                <tr
-                  aria-labelledby="left-button-FILE left-content-FILE right-button-FILE right-content-FILE"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="both"
-                  right-type="both"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="FILE"></td>
-                  <td class="gr-diff left lineNum" data-value="FILE">
-                    <button
-                      aria-label="Add file comment"
-                      class="gr-diff left lineNumButton"
-                      data-value="FILE"
-                      id="left-button-FILE"
-                      tabindex="-1"
-                    >
-                      File
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info sign"></td>
-                  <td class="both content file gr-diff left no-intraline-info">
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="FILE">
-                    <button
-                      aria-label="Add file comment"
-                      class="gr-diff lineNumButton right"
-                      data-value="FILE"
-                      id="right-button-FILE"
-                      tabindex="-1"
-                    >
-                      File
-                    </button>
-                  </td>
-                  <td class="gr-diff no-intraline-info right sign"></td>
-                  <td class="both content file gr-diff no-intraline-info right">
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-              </tbody>
-              <tbody class="both gr-diff section">
-                <tr
-                  aria-labelledby="left-button-1 left-content-1 right-button-1 right-content-1"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="both"
-                  right-type="both"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="1"></td>
-                  <td class="gr-diff left lineNum" data-value="1">
-                    <button
-                      aria-label="1 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="1"
-                      id="left-button-1"
-                      tabindex="-1"
-                    >
-                      1
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info sign"></td>
-                  <td class="both content gr-diff left no-intraline-info">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-1"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="1">
-                    <button
-                      aria-label="1 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="1"
-                      id="right-button-1"
-                      tabindex="-1"
-                    >
-                      1
-                    </button>
-                  </td>
-                  <td class="gr-diff no-intraline-info right sign"></td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-1"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-2 left-content-2 right-button-2 right-content-2"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="both"
-                  right-type="both"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="2"></td>
-                  <td class="gr-diff left lineNum" data-value="2">
-                    <button
-                      aria-label="2 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="2"
-                      id="left-button-2"
-                      tabindex="-1"
-                    >
-                      2
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info sign"></td>
-                  <td class="both content gr-diff left no-intraline-info">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-2"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="2">
-                    <button
-                      aria-label="2 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="2"
-                      id="right-button-2"
-                      tabindex="-1"
-                    >
-                      2
-                    </button>
-                  </td>
-                  <td class="gr-diff no-intraline-info right sign"></td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-2"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-3 left-content-3 right-button-3 right-content-3"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="both"
-                  right-type="both"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="3"></td>
-                  <td class="gr-diff left lineNum" data-value="3">
-                    <button
-                      aria-label="3 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="3"
-                      id="left-button-3"
-                      tabindex="-1"
-                    >
-                      3
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info sign"></td>
-                  <td class="both content gr-diff left no-intraline-info">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-3"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="3">
-                    <button
-                      aria-label="3 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="3"
-                      id="right-button-3"
-                      tabindex="-1"
-                    >
-                      3
-                    </button>
-                  </td>
-                  <td class="gr-diff no-intraline-info right sign"></td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-3"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-4 left-content-4 right-button-4 right-content-4"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="both"
-                  right-type="both"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="4"></td>
-                  <td class="gr-diff left lineNum" data-value="4">
-                    <button
-                      aria-label="4 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="4"
-                      id="left-button-4"
-                      tabindex="-1"
-                    >
-                      4
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info sign"></td>
-                  <td class="both content gr-diff left no-intraline-info">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-4"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="4">
-                    <button
-                      aria-label="4 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="4"
-                      id="right-button-4"
-                      tabindex="-1"
-                    >
-                      4
-                    </button>
-                  </td>
-                  <td class="gr-diff no-intraline-info right sign"></td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-4"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-              </tbody>
-              <tbody class="delta gr-diff section total">
-                <tr
-                  aria-labelledby="right-button-5 right-content-5"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="blank"
-                  right-type="add"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="0"></td>
-                  <td class="blankLineNum gr-diff left"></td>
-                  <td class="blank gr-diff left no-intraline-info sign"></td>
-                  <td class="blank gr-diff left no-intraline-info">
-                    <div class="contentText gr-diff" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="5">
-                    <button
-                      aria-label="5 added"
-                      class="gr-diff lineNumButton right"
-                      data-value="5"
-                      id="right-button-5"
-                      tabindex="-1"
-                    >
-                      5
-                    </button>
-                  </td>
-                  <td class="add gr-diff no-intraline-info right sign">+</td>
-                  <td class="add content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-5"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="right-button-6 right-content-6"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="blank"
-                  right-type="add"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="0"></td>
-                  <td class="blankLineNum gr-diff left"></td>
-                  <td class="blank gr-diff left no-intraline-info sign"></td>
-                  <td class="blank gr-diff left no-intraline-info">
-                    <div class="contentText gr-diff" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="6">
-                    <button
-                      aria-label="6 added"
-                      class="gr-diff lineNumButton right"
-                      data-value="6"
-                      id="right-button-6"
-                      tabindex="-1"
-                    >
-                      6
-                    </button>
-                  </td>
-                  <td class="add gr-diff no-intraline-info right sign">+</td>
-                  <td class="add content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-6"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="right-button-7 right-content-7"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="blank"
-                  right-type="add"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="0"></td>
-                  <td class="blankLineNum gr-diff left"></td>
-                  <td class="blank gr-diff left no-intraline-info sign"></td>
-                  <td class="blank gr-diff left no-intraline-info">
-                    <div class="contentText gr-diff" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="7">
-                    <button
-                      aria-label="7 added"
-                      class="gr-diff lineNumButton right"
-                      data-value="7"
-                      id="right-button-7"
-                      tabindex="-1"
-                    >
-                      7
-                    </button>
-                  </td>
-                  <td class="add gr-diff no-intraline-info right sign">+</td>
-                  <td class="add content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-7"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-              </tbody>
-              <tbody class="both gr-diff section">
-                <tr
-                  aria-labelledby="left-button-5 left-content-5 right-button-8 right-content-8"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="both"
-                  right-type="both"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="5"></td>
-                  <td class="gr-diff left lineNum" data-value="5">
-                    <button
-                      aria-label="5 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="5"
-                      id="left-button-5"
-                      tabindex="-1"
-                    >
-                      5
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info sign"></td>
-                  <td class="both content gr-diff left no-intraline-info">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-5"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="8">
-                    <button
-                      aria-label="8 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="8"
-                      id="right-button-8"
-                      tabindex="-1"
-                    >
-                      8
-                    </button>
-                  </td>
-                  <td class="gr-diff no-intraline-info right sign"></td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-8"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-6 left-content-6 right-button-9 right-content-9"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="both"
-                  right-type="both"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="6"></td>
-                  <td class="gr-diff left lineNum" data-value="6">
-                    <button
-                      aria-label="6 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="6"
-                      id="left-button-6"
-                      tabindex="-1"
-                    >
-                      6
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info sign"></td>
-                  <td class="both content gr-diff left no-intraline-info">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-6"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="9">
-                    <button
-                      aria-label="9 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="9"
-                      id="right-button-9"
-                      tabindex="-1"
-                    >
-                      9
-                    </button>
-                  </td>
-                  <td class="gr-diff no-intraline-info right sign"></td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-9"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-7 left-content-7 right-button-10 right-content-10"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="both"
-                  right-type="both"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="7"></td>
-                  <td class="gr-diff left lineNum" data-value="7">
-                    <button
-                      aria-label="7 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="7"
-                      id="left-button-7"
-                      tabindex="-1"
-                    >
-                      7
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info sign"></td>
-                  <td class="both content gr-diff left no-intraline-info">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-7"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="10">
-                    <button
-                      aria-label="10 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="10"
-                      id="right-button-10"
-                      tabindex="-1"
-                    >
-                      10
-                    </button>
-                  </td>
-                  <td class="gr-diff no-intraline-info right sign"></td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-10"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-8 left-content-8 right-button-11 right-content-11"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="both"
-                  right-type="both"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="8"></td>
-                  <td class="gr-diff left lineNum" data-value="8">
-                    <button
-                      aria-label="8 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="8"
-                      id="left-button-8"
-                      tabindex="-1"
-                    >
-                      8
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info sign"></td>
-                  <td class="both content gr-diff left no-intraline-info">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-8"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="11">
-                    <button
-                      aria-label="11 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="11"
-                      id="right-button-11"
-                      tabindex="-1"
-                    >
-                      11
-                    </button>
-                  </td>
-                  <td class="gr-diff no-intraline-info right sign"></td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-11"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-9 left-content-9 right-button-12 right-content-12"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="both"
-                  right-type="both"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="9"></td>
-                  <td class="gr-diff left lineNum" data-value="9">
-                    <button
-                      aria-label="9 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="9"
-                      id="left-button-9"
-                      tabindex="-1"
-                    >
-                      9
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info sign"></td>
-                  <td class="both content gr-diff left no-intraline-info">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-9"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="12">
-                    <button
-                      aria-label="12 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="12"
-                      id="right-button-12"
-                      tabindex="-1"
-                    >
-                      12
-                    </button>
-                  </td>
-                  <td class="gr-diff no-intraline-info right sign"></td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-12"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-              </tbody>
-              <tbody class="delta gr-diff section total">
-                <tr
-                  aria-labelledby="left-button-10 left-content-10"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="remove"
-                  right-type="blank"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="10"></td>
-                  <td class="gr-diff left lineNum" data-value="10">
-                    <button
-                      aria-label="10 removed"
-                      class="gr-diff left lineNumButton"
-                      data-value="10"
-                      id="left-button-10"
-                      tabindex="-1"
-                    >
-                      10
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info remove sign">-</td>
-                  <td class="content gr-diff left no-intraline-info remove">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-10"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="blankLineNum gr-diff right"></td>
-                  <td class="blank gr-diff no-intraline-info right sign"></td>
-                  <td class="blank gr-diff no-intraline-info right">
-                    <div class="contentText gr-diff" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-11 left-content-11"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="remove"
-                  right-type="blank"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="11"></td>
-                  <td class="gr-diff left lineNum" data-value="11">
-                    <button
-                      aria-label="11 removed"
-                      class="gr-diff left lineNumButton"
-                      data-value="11"
-                      id="left-button-11"
-                      tabindex="-1"
-                    >
-                      11
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info remove sign">-</td>
-                  <td class="content gr-diff left no-intraline-info remove">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-11"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="blankLineNum gr-diff right"></td>
-                  <td class="blank gr-diff no-intraline-info right sign"></td>
-                  <td class="blank gr-diff no-intraline-info right">
-                    <div class="contentText gr-diff" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-12 left-content-12"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="remove"
-                  right-type="blank"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="12"></td>
-                  <td class="gr-diff left lineNum" data-value="12">
-                    <button
-                      aria-label="12 removed"
-                      class="gr-diff left lineNumButton"
-                      data-value="12"
-                      id="left-button-12"
-                      tabindex="-1"
-                    >
-                      12
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info remove sign">-</td>
-                  <td class="content gr-diff left no-intraline-info remove">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-12"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="blankLineNum gr-diff right"></td>
-                  <td class="blank gr-diff no-intraline-info right sign"></td>
-                  <td class="blank gr-diff no-intraline-info right">
-                    <div class="contentText gr-diff" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-13 left-content-13"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="remove"
-                  right-type="blank"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="13"></td>
-                  <td class="gr-diff left lineNum" data-value="13">
-                    <button
-                      aria-label="13 removed"
-                      class="gr-diff left lineNumButton"
-                      data-value="13"
-                      id="left-button-13"
-                      tabindex="-1"
-                    >
-                      13
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info remove sign">-</td>
-                  <td class="content gr-diff left no-intraline-info remove">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-13"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="blankLineNum gr-diff right"></td>
-                  <td class="blank gr-diff no-intraline-info right sign"></td>
-                  <td class="blank gr-diff no-intraline-info right">
-                    <div class="contentText gr-diff" data-side="right"></div>
-                  </td>
-                </tr>
-              </tbody>
-              <tbody class="delta gr-diff ignoredWhitespaceOnly section">
-                <tr
-                  aria-labelledby="left-button-14 left-content-14 right-button-13 right-content-13"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="remove"
-                  right-type="add"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="14"></td>
-                  <td class="gr-diff left lineNum" data-value="14">
-                    <button
-                      aria-label="14 removed"
-                      class="gr-diff left lineNumButton"
-                      data-value="14"
-                      id="left-button-14"
-                      tabindex="-1"
-                    >
-                      14
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info remove sign">-</td>
-                  <td class="content gr-diff left no-intraline-info remove">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-14"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="13">
-                    <button
-                      aria-label="13 added"
-                      class="gr-diff lineNumButton right"
-                      data-value="13"
-                      id="right-button-13"
-                      tabindex="-1"
-                    >
-                      13
-                    </button>
-                  </td>
-                  <td class="add gr-diff no-intraline-info right sign">+</td>
-                  <td class="add content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-13"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-15 left-content-15 right-button-14 right-content-14"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="remove"
-                  right-type="add"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="15"></td>
-                  <td class="gr-diff left lineNum" data-value="15">
-                    <button
-                      aria-label="15 removed"
-                      class="gr-diff left lineNumButton"
-                      data-value="15"
-                      id="left-button-15"
-                      tabindex="-1"
-                    >
-                      15
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info remove sign">-</td>
-                  <td class="content gr-diff left no-intraline-info remove">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-15"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="14">
-                    <button
-                      aria-label="14 added"
-                      class="gr-diff lineNumButton right"
-                      data-value="14"
-                      id="right-button-14"
-                      tabindex="-1"
-                    >
-                      14
-                    </button>
-                  </td>
-                  <td class="add gr-diff no-intraline-info right sign">+</td>
-                  <td class="add content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-14"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-              </tbody>
-              <tbody class="delta gr-diff section">
-                <tr
-                  aria-labelledby="left-button-16 left-content-16 right-button-15 right-content-15"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="remove"
-                  right-type="add"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="16"></td>
-                  <td class="gr-diff left lineNum" data-value="16">
-                    <button
-                      aria-label="16 removed"
-                      class="gr-diff left lineNumButton"
-                      data-value="16"
-                      id="left-button-16"
-                      tabindex="-1"
-                    >
-                      16
-                    </button>
-                  </td>
-                  <td class="gr-diff left remove sign">-</td>
-                  <td class="content gr-diff left remove">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-16"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="15">
-                    <button
-                      aria-label="15 added"
-                      class="gr-diff lineNumButton right"
-                      data-value="15"
-                      id="right-button-15"
-                      tabindex="-1"
-                    >
-                      15
-                    </button>
-                  </td>
-                  <td class="add gr-diff right sign">+</td>
-                  <td class="add content gr-diff right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-15"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-              </tbody>
-              <tbody class="both gr-diff section">
-                <tr
-                  aria-labelledby="left-button-17 left-content-17 right-button-16 right-content-16"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="both"
-                  right-type="both"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="17"></td>
-                  <td class="gr-diff left lineNum" data-value="17">
-                    <button
-                      aria-label="17 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="17"
-                      id="left-button-17"
-                      tabindex="-1"
-                    >
-                      17
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info sign"></td>
-                  <td class="both content gr-diff left no-intraline-info">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-17"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="16">
-                    <button
-                      aria-label="16 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="16"
-                      id="right-button-16"
-                      tabindex="-1"
-                    >
-                      16
-                    </button>
-                  </td>
-                  <td class="gr-diff no-intraline-info right sign"></td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-16"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-18 left-content-18 right-button-17 right-content-17"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="both"
-                  right-type="both"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="18"></td>
-                  <td class="gr-diff left lineNum" data-value="18">
-                    <button
-                      aria-label="18 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="18"
-                      id="left-button-18"
-                      tabindex="-1"
-                    >
-                      18
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info sign"></td>
-                  <td class="both content gr-diff left no-intraline-info">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-18"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="17">
-                    <button
-                      aria-label="17 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="17"
-                      id="right-button-17"
-                      tabindex="-1"
-                    >
-                      17
-                    </button>
-                  </td>
-                  <td class="gr-diff no-intraline-info right sign"></td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-17"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-19 left-content-19 right-button-18 right-content-18"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="both"
-                  right-type="both"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="19"></td>
-                  <td class="gr-diff left lineNum" data-value="19">
-                    <button
-                      aria-label="19 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="19"
-                      id="left-button-19"
-                      tabindex="-1"
-                    >
-                      19
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info sign"></td>
-                  <td class="both content gr-diff left no-intraline-info">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-19"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="18">
-                    <button
-                      aria-label="18 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="18"
-                      id="right-button-18"
-                      tabindex="-1"
-                    >
-                      18
-                    </button>
-                  </td>
-                  <td class="gr-diff no-intraline-info right sign"></td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-18"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-              </tbody>
-              <tbody class="contextControl gr-diff section">
-                <tr
-                  class="above contextBackground gr-diff side-by-side"
-                  left-type="contextControl"
-                  right-type="contextControl"
-                >
-                  <td class="blame gr-diff" data-line-number="0"></td>
-                  <td class="contextLineNum gr-diff"></td>
-                  <td class="gr-diff sign"></td>
-                  <td class="gr-diff"></td>
-                  <td class="contextLineNum gr-diff"></td>
-                  <td class="gr-diff sign"></td>
-                  <td class="gr-diff"></td>
-                </tr>
-                <tr class="dividerRow gr-diff show-both">
-                  <td class="blame gr-diff" data-line-number="0"></td>
-                  <td class="gr-diff"></td>
-                  <td class="dividerCell gr-diff" colspan="3">
-                    <gr-context-controls
-                      class="gr-diff"
-                      showconfig="both"
-                    ></gr-context-controls>
-                  </td>
-                </tr>
-                <tr
-                  class="below contextBackground gr-diff side-by-side"
-                  left-type="contextControl"
-                  right-type="contextControl"
-                >
-                  <td class="blame gr-diff" data-line-number="0"></td>
-                  <td class="contextLineNum gr-diff"></td>
-                  <td class="gr-diff sign"></td>
-                  <td class="gr-diff"></td>
-                  <td class="contextLineNum gr-diff"></td>
-                  <td class="gr-diff sign"></td>
-                  <td class="gr-diff"></td>
-                </tr>
-              </tbody>
-              <tbody class="both gr-diff section">
-                <tr
-                  aria-labelledby="left-button-38 left-content-38 right-button-37 right-content-37"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="both"
-                  right-type="both"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="38"></td>
-                  <td class="gr-diff left lineNum" data-value="38">
-                    <button
-                      aria-label="38 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="38"
-                      id="left-button-38"
-                      tabindex="-1"
-                    >
-                      38
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info sign"></td>
-                  <td class="both content gr-diff left no-intraline-info">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-38"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="37">
-                    <button
-                      aria-label="37 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="37"
-                      id="right-button-37"
-                      tabindex="-1"
-                    >
-                      37
-                    </button>
-                  </td>
-                  <td class="gr-diff no-intraline-info right sign"></td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-37"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-39 left-content-39 right-button-38 right-content-38"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="both"
-                  right-type="both"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="39"></td>
-                  <td class="gr-diff left lineNum" data-value="39">
-                    <button
-                      aria-label="39 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="39"
-                      id="left-button-39"
-                      tabindex="-1"
-                    >
-                      39
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info sign"></td>
-                  <td class="both content gr-diff left no-intraline-info">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-39"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="38">
-                    <button
-                      aria-label="38 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="38"
-                      id="right-button-38"
-                      tabindex="-1"
-                    >
-                      38
-                    </button>
-                  </td>
-                  <td class="gr-diff no-intraline-info right sign"></td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-38"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-40 left-content-40 right-button-39 right-content-39"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="both"
-                  right-type="both"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="40"></td>
-                  <td class="gr-diff left lineNum" data-value="40">
-                    <button
-                      aria-label="40 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="40"
-                      id="left-button-40"
-                      tabindex="-1"
-                    >
-                      40
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info sign"></td>
-                  <td class="both content gr-diff left no-intraline-info">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-40"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="39">
-                    <button
-                      aria-label="39 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="39"
-                      id="right-button-39"
-                      tabindex="-1"
-                    >
-                      39
-                    </button>
-                  </td>
-                  <td class="gr-diff no-intraline-info right sign"></td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-39"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-              </tbody>
-              <tbody class="delta gr-diff section total">
-                <tr
-                  aria-labelledby="right-button-40 right-content-40"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="blank"
-                  right-type="add"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="0"></td>
-                  <td class="blankLineNum gr-diff left"></td>
-                  <td class="blank gr-diff left no-intraline-info sign"></td>
-                  <td class="blank gr-diff left no-intraline-info">
-                    <div class="contentText gr-diff" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="40">
-                    <button
-                      aria-label="40 added"
-                      class="gr-diff lineNumButton right"
-                      data-value="40"
-                      id="right-button-40"
-                      tabindex="-1"
-                    >
-                      40
-                    </button>
-                  </td>
-                  <td class="add gr-diff no-intraline-info right sign">+</td>
-                  <td class="add content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-40"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="right-button-41 right-content-41"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="blank"
-                  right-type="add"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="0"></td>
-                  <td class="blankLineNum gr-diff left"></td>
-                  <td class="blank gr-diff left no-intraline-info sign"></td>
-                  <td class="blank gr-diff left no-intraline-info">
-                    <div class="contentText gr-diff" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="41">
-                    <button
-                      aria-label="41 added"
-                      class="gr-diff lineNumButton right"
-                      data-value="41"
-                      id="right-button-41"
-                      tabindex="-1"
-                    >
-                      41
-                    </button>
-                  </td>
-                  <td class="add gr-diff no-intraline-info right sign">+</td>
-                  <td class="add content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-41"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="right-button-42 right-content-42"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="blank"
-                  right-type="add"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="0"></td>
-                  <td class="blankLineNum gr-diff left"></td>
-                  <td class="blank gr-diff left no-intraline-info sign"></td>
-                  <td class="blank gr-diff left no-intraline-info">
-                    <div class="contentText gr-diff" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="42">
-                    <button
-                      aria-label="42 added"
-                      class="gr-diff lineNumButton right"
-                      data-value="42"
-                      id="right-button-42"
-                      tabindex="-1"
-                    >
-                      42
-                    </button>
-                  </td>
-                  <td class="add gr-diff no-intraline-info right sign">+</td>
-                  <td class="add content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-42"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="right-button-43 right-content-43"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="blank"
-                  right-type="add"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="0"></td>
-                  <td class="blankLineNum gr-diff left"></td>
-                  <td class="blank gr-diff left no-intraline-info sign"></td>
-                  <td class="blank gr-diff left no-intraline-info">
-                    <div class="contentText gr-diff" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="43">
-                    <button
-                      aria-label="43 added"
-                      class="gr-diff lineNumButton right"
-                      data-value="43"
-                      id="right-button-43"
-                      tabindex="-1"
-                    >
-                      43
-                    </button>
-                  </td>
-                  <td class="add gr-diff no-intraline-info right sign">+</td>
-                  <td class="add content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-43"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-              </tbody>
-              <tbody class="both gr-diff section">
-                <tr
-                  aria-labelledby="left-button-41 left-content-41 right-button-44 right-content-44"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="both"
-                  right-type="both"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="41"></td>
-                  <td class="gr-diff left lineNum" data-value="41">
-                    <button
-                      aria-label="41 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="41"
-                      id="left-button-41"
-                      tabindex="-1"
-                    >
-                      41
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info sign"></td>
-                  <td class="both content gr-diff left no-intraline-info">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-41"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="44">
-                    <button
-                      aria-label="44 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="44"
-                      id="right-button-44"
-                      tabindex="-1"
-                    >
-                      44
-                    </button>
-                  </td>
-                  <td class="gr-diff no-intraline-info right sign"></td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-44"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-42 left-content-42 right-button-45 right-content-45"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="both"
-                  right-type="both"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="42"></td>
-                  <td class="gr-diff left lineNum" data-value="42">
-                    <button
-                      aria-label="42 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="42"
-                      id="left-button-42"
-                      tabindex="-1"
-                    >
-                      42
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info sign"></td>
-                  <td class="both content gr-diff left no-intraline-info">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-42"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="45">
-                    <button
-                      aria-label="45 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="45"
-                      id="right-button-45"
-                      tabindex="-1"
-                    >
-                      45
-                    </button>
-                  </td>
-                  <td class="gr-diff no-intraline-info right sign"></td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-45"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-43 left-content-43 right-button-46 right-content-46"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="both"
-                  right-type="both"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="43"></td>
-                  <td class="gr-diff left lineNum" data-value="43">
-                    <button
-                      aria-label="43 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="43"
-                      id="left-button-43"
-                      tabindex="-1"
-                    >
-                      43
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info sign"></td>
-                  <td class="both content gr-diff left no-intraline-info">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-43"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="46">
-                    <button
-                      aria-label="46 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="46"
-                      id="right-button-46"
-                      tabindex="-1"
-                    >
-                      46
-                    </button>
-                  </td>
-                  <td class="gr-diff no-intraline-info right sign"></td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-46"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-44 left-content-44 right-button-47 right-content-47"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="both"
-                  right-type="both"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="44"></td>
-                  <td class="gr-diff left lineNum" data-value="44">
-                    <button
-                      aria-label="44 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="44"
-                      id="left-button-44"
-                      tabindex="-1"
-                    >
-                      44
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info sign"></td>
-                  <td class="both content gr-diff left no-intraline-info">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-44"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="47">
-                    <button
-                      aria-label="47 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="47"
-                      id="right-button-47"
-                      tabindex="-1"
-                    >
-                      47
-                    </button>
-                  </td>
-                  <td class="gr-diff no-intraline-info right sign"></td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-47"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-                <tr
-                  aria-labelledby="left-button-45 left-content-45 right-button-48 right-content-48"
-                  class="diff-row gr-diff side-by-side"
-                  left-type="both"
-                  right-type="both"
-                  tabindex="-1"
-                >
-                  <td class="blame gr-diff" data-line-number="45"></td>
-                  <td class="gr-diff left lineNum" data-value="45">
-                    <button
-                      aria-label="45 unmodified"
-                      class="gr-diff left lineNumButton"
-                      data-value="45"
-                      id="left-button-45"
-                      tabindex="-1"
-                    >
-                      45
-                    </button>
-                  </td>
-                  <td class="gr-diff left no-intraline-info sign"></td>
-                  <td class="both content gr-diff left no-intraline-info">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="left"
-                      id="left-content-45"
-                    ></div>
-                    <div class="thread-group" data-side="left"></div>
-                  </td>
-                  <td class="gr-diff lineNum right" data-value="48">
-                    <button
-                      aria-label="48 unmodified"
-                      class="gr-diff lineNumButton right"
-                      data-value="48"
-                      id="right-button-48"
-                      tabindex="-1"
-                    >
-                      48
-                    </button>
-                  </td>
-                  <td class="gr-diff no-intraline-info right sign"></td>
-                  <td class="both content gr-diff no-intraline-info right">
-                    <div
-                      class="contentText gr-diff"
-                      data-side="right"
-                      id="right-content-48"
-                    ></div>
-                    <div class="thread-group" data-side="right"></div>
-                  </td>
-                </tr>
-              </tbody>
-            </table>
-          </div>
-        `,
-        {
-          ignoreTags: [
-            'gr-context-controls-section',
-            'gr-diff-section',
-            'gr-diff-row',
-            'gr-diff-text',
-            'gr-legacy-text',
-            'slot',
-          ],
-        }
-      );
-    });
-  });
-
-  suite('selectionchange event handling', () => {
-    let handleSelectionChangeStub: sinon.SinonSpy;
-
-    const emulateSelection = function () {
-      document.dispatchEvent(new CustomEvent('selectionchange'));
-    };
-
-    setup(async () => {
-      handleSelectionChangeStub = sinon.spy(
-        element.highlights,
-        'handleSelectionChange'
-      );
-    });
-
-    test('enabled if logged in', async () => {
-      element.loggedIn = true;
-      await element.updateComplete;
-      emulateSelection();
-      assert.isTrue(handleSelectionChangeStub.called);
-    });
-
-    test('ignored if logged out', async () => {
-      element.loggedIn = false;
-      await element.updateComplete;
-      emulateSelection();
-      assert.isFalse(handleSelectionChangeStub.called);
-    });
-  });
-
-  test('cancel', () => {
-    const cleanupStub = sinon.stub(element.diffBuilder, 'cleanup');
-    element.cancel();
-    assert.isTrue(cleanupStub.calledOnce);
-  });
-
-  test('line limit with line_wrapping', async () => {
-    element.prefs = {...MINIMAL_PREFS, line_wrapping: true};
-    await element.updateComplete;
-    assert.equal(getComputedStyleValue('--line-limit-marker', element), '80ch');
-  });
-
-  test('line limit without line_wrapping', async () => {
-    element.prefs = {...MINIMAL_PREFS, line_wrapping: false};
-    await element.updateComplete;
-    assert.equal(getComputedStyleValue('--line-limit-marker', element), '-1px');
-  });
-
-  suite('FULL_RESPONSIVE mode', () => {
-    setup(async () => {
-      element.prefs = {...MINIMAL_PREFS};
-      element.renderPrefs = {responsive_mode: 'FULL_RESPONSIVE'};
-      await element.updateComplete;
-    });
-
-    test('line limit is based on line_length', async () => {
-      element.prefs = {...element.prefs!, line_length: 100};
-      await element.updateComplete;
-      assert.equal(
-        getComputedStyleValue('--line-limit-marker', element),
-        '100ch'
-      );
-    });
-
-    test('content-width should not be defined', () => {
-      assert.equal(getComputedStyleValue('--content-width', element), 'none');
-    });
-  });
-
-  suite('SHRINK_ONLY mode', () => {
-    setup(async () => {
-      element.prefs = {...MINIMAL_PREFS};
-      element.renderPrefs = {responsive_mode: 'SHRINK_ONLY'};
-      await element.updateComplete;
-    });
-
-    test('content-width should not be defined', () => {
-      assert.equal(getComputedStyleValue('--content-width', element), 'none');
-    });
-
-    test('max-width considers two content columns in side-by-side', async () => {
-      element.viewMode = DiffViewMode.SIDE_BY_SIDE;
-      await element.updateComplete;
-      assert.equal(
-        getComputedStyleValue('--diff-max-width', element),
-        'calc(2 * 80ch + 2 * 48px + 0ch + 1px + 2px)'
-      );
-    });
-
-    test('max-width considers one content column in unified', async () => {
-      element.viewMode = DiffViewMode.UNIFIED;
-      await element.updateComplete;
-      assert.equal(
-        getComputedStyleValue('--diff-max-width', element),
-        'calc(1 * 80ch + 2 * 48px + 0ch + 1px + 2px)'
-      );
-    });
-
-    test('max-width considers font-size', async () => {
-      element.prefs = {...element.prefs!, font_size: 13};
-      await element.updateComplete;
-      // Each line number column: 4 * 13 = 52px
-      assert.equal(
-        getComputedStyleValue('--diff-max-width', element),
-        'calc(2 * 80ch + 2 * 52px + 0ch + 1px + 2px)'
-      );
-    });
-
-    test('sign cols are considered if show_sign_col is true', async () => {
-      element.renderPrefs = {...element.renderPrefs, show_sign_col: true};
-      await element.updateComplete;
-      assert.equal(
-        getComputedStyleValue('--diff-max-width', element),
-        'calc(2 * 80ch + 2 * 48px + 2ch + 1px + 2px)'
-      );
-    });
-  });
-
-  suite('not logged in', () => {
-    setup(async () => {
-      element.loggedIn = false;
-      await element.updateComplete;
-    });
-
-    test('toggleLeftDiff', () => {
-      element.toggleLeftDiff();
-      assert.isTrue(element.classList.contains('no-left'));
-      element.toggleLeftDiff();
-      assert.isFalse(element.classList.contains('no-left'));
-    });
-
-    suite('binary diffs', () => {
-      test('render binary diff', async () => {
-        element.prefs = {
-          ...MINIMAL_PREFS,
-        };
-        element.diff = {
-          meta_a: {name: 'carrot.exe', content_type: 'binary', lines: 0},
-          meta_b: {name: 'carrot.exe', content_type: 'binary', lines: 0},
-          change_type: 'MODIFIED',
-          intraline_status: 'OK',
-          diff_header: [],
-          content: [],
-          binary: true,
-        };
-        await waitForEventOnce(element, 'render');
-
-        assert.shadowDom.equal(
-          element,
-          /* HTML */ `
-            <div class="diffContainer oldDiff sideBySide">
-              <gr-diff-section class="left-FILE right-FILE"> </gr-diff-section>
-              <gr-diff-row class="left-FILE right-FILE"> </gr-diff-row>
-              <table class="selected-right" id="diffTable">
-                <colgroup>
-                  <col class="blame gr-diff" />
-                  <col class="gr-diff left" width="48" />
-                  <col class="gr-diff left sign" />
-                  <col class="gr-diff left" />
-                  <col class="gr-diff right" width="48" />
-                  <col class="gr-diff right sign" />
-                  <col class="gr-diff right" />
-                </colgroup>
-                <tbody class="binary-diff gr-diff"></tbody>
-                <tbody class="both gr-diff section">
-                  <tr
-                    aria-labelledby="left-button-FILE left-content-FILE right-button-FILE right-content-FILE"
-                    class="diff-row gr-diff side-by-side"
-                    left-type="both"
-                    right-type="both"
-                    tabindex="-1"
-                  >
-                    <td class="blame gr-diff" data-line-number="FILE"></td>
-                    <td class="gr-diff left lineNum" data-value="FILE">
-                      <button
-                        aria-label="Add file comment"
-                        class="gr-diff left lineNumButton"
-                        data-value="FILE"
-                        id="left-button-FILE"
-                        tabindex="-1"
-                      >
-                        File
-                      </button>
-                    </td>
-                    <td class="gr-diff left no-intraline-info sign"></td>
-                    <td
-                      class="both content file gr-diff left no-intraline-info"
-                    >
-                      <div class="thread-group" data-side="left">
-                        <slot name="left-FILE"> </slot>
-                      </div>
-                    </td>
-                    <td class="gr-diff lineNum right" data-value="FILE">
-                      <button
-                        aria-label="Add file comment"
-                        class="gr-diff lineNumButton right"
-                        data-value="FILE"
-                        id="right-button-FILE"
-                        tabindex="-1"
-                      >
-                        File
-                      </button>
-                    </td>
-                    <td class="gr-diff no-intraline-info right sign"></td>
-                    <td
-                      class="both content file gr-diff no-intraline-info right"
-                    >
-                      <div class="thread-group" data-side="right">
-                        <slot name="right-FILE"> </slot>
-                      </div>
-                    </td>
-                  </tr>
-                </tbody>
-                <tbody class="binary-diff gr-diff">
-                  <tr class="gr-diff">
-                    <td class="gr-diff" colspan="5">
-                      <span> Difference in binary files </span>
-                    </td>
-                  </tr>
-                </tbody>
-              </table>
-            </div>
-          `
-        );
-      });
-    });
-
-    suite('image diffs', () => {
-      let mockFile1: ImageInfo;
-      let mockFile2: ImageInfo;
-      setup(() => {
-        mockFile1 = {
-          body:
-            'Qk06AAAAAAAAADYAAAAoAAAAAQAAAP////8BACAAAAAAAAAAAAATCwAAE' +
-            'wsAAAAAAAAAAAAAAAAA/w==',
-          type: 'image/bmp',
-        };
-        mockFile2 = {
-          body:
-            'Qk06AAAAAAAAADYAAAAoAAAAAQAAAP////8BACAAAAAAAAAAAAATCwAAE' +
-            'wsAAAAAAAAAAAAA/////w==',
-          type: 'image/bmp',
-        };
-
-        element.prefs = {
-          context: 10,
-          cursor_blink_rate: 0,
-          font_size: 12,
-          ignore_whitespace: 'IGNORE_NONE',
-          line_length: 100,
-          line_wrapping: false,
-          show_line_endings: true,
-          show_tabs: true,
-          show_whitespace_errors: true,
-          syntax_highlighting: true,
-          tab_size: 8,
-        };
-      });
-
-      test('render image diff', async () => {
-        element.baseImage = mockFile1;
-        element.revisionImage = mockFile2;
-        element.diff = {
-          meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 66},
-          meta_b: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 560},
-          intraline_status: 'OK',
-          change_type: 'MODIFIED',
-          diff_header: [
-            'diff --git a/carrot.jpg b/carrot.jpg',
-            'index 2adc47d..f9c2f2c 100644',
-            '--- a/carrot.jpg',
-            '+++ b/carrot.jpg',
-            'Binary files differ',
-          ],
-          content: [{skip: 66}],
-          binary: true,
-        };
-
-        await waitForEventOnce(element, 'render');
-        const imageDiffSection = queryAndAssert(element, 'tbody.image-diff');
-        assert.lightDom.equal(
-          imageDiffSection,
-          /* HTML */ `
-            <tbody class="gr-diff image-diff">
-              <tr class="gr-diff">
-                <td class="blank gr-diff left lineNum"></td>
-                <td class="gr-diff left">
-                  <img
-                    class="gr-diff left"
-                    src="data:image/bmp;base64,${mockFile1.body}"
-                  />
-                </td>
-                <td class="blank gr-diff lineNum right"></td>
-                <td class="gr-diff right">
-                  <img
-                    class="gr-diff right"
-                    src="data:image/bmp;base64,${mockFile2.body}"
-                  />
-                </td>
-              </tr>
-              <tr class="gr-diff">
-                <td class="blank gr-diff left lineNum"></td>
-                <td class="gr-diff left">
-                  <label class="gr-diff">
-                    <span class="gr-diff label"> image/bmp </span>
-                  </label>
-                </td>
-                <td class="blank gr-diff lineNum right"></td>
-                <td class="gr-diff right">
-                  <label class="gr-diff">
-                    <span class="gr-diff label"> image/bmp </span>
-                  </label>
-                </td>
-              </tr>
-            </tbody>
-          `
-        );
-        const endpoint = queryAndAssert(element, 'tbody.endpoint');
-        assert.dom.equal(
-          endpoint,
-          /* HTML */ `
-            <tbody class="gr-diff endpoint">
-              <tr class="gr-diff">
-                <gr-endpoint-decorator class="gr-diff" name="image-diff">
-                  <gr-endpoint-param class="gr-diff" name="baseImage">
-                  </gr-endpoint-param>
-                  <gr-endpoint-param class="gr-diff" name="revisionImage">
-                  </gr-endpoint-param>
-                </gr-endpoint-decorator>
-              </tr>
-            </tbody>
-          `
-        );
-      });
-
-      test('renders image diffs with a different file name', async () => {
-        const mockDiff: DiffInfo = {
-          meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 66},
-          meta_b: {name: 'carrot2.jpg', content_type: 'image/jpeg', lines: 560},
-          intraline_status: 'OK',
-          change_type: 'MODIFIED',
-          diff_header: [
-            'diff --git a/carrot.jpg b/carrot2.jpg',
-            'index 2adc47d..f9c2f2c 100644',
-            '--- a/carrot.jpg',
-            '+++ b/carrot2.jpg',
-            'Binary files differ',
-          ],
-          content: [{skip: 66}],
-          binary: true,
-        };
-
-        element.baseImage = mockFile1;
-        element.baseImage._name = mockDiff.meta_a!.name;
-        element.revisionImage = mockFile2;
-        element.revisionImage._name = mockDiff.meta_b!.name;
-        element.diff = mockDiff;
-
-        await waitForEventOnce(element, 'render');
-        const imageDiffSection = queryAndAssert(element, 'tbody.image-diff');
-        const leftLabel = queryAndAssert(imageDiffSection, 'td.left label');
-        const rightLabel = queryAndAssert(imageDiffSection, 'td.right label');
-        assert.dom.equal(
-          leftLabel,
-          /* HTML */ `
-            <label class="gr-diff">
-              <span class="gr-diff name"> carrot.jpg </span>
-              <br class="gr-diff" />
-              <span class="gr-diff label"> image/bmp </span>
-            </label>
-          `
-        );
-        assert.dom.equal(
-          rightLabel,
-          /* HTML */ `
-            <label class="gr-diff">
-              <span class="gr-diff name"> carrot2.jpg </span>
-              <br class="gr-diff" />
-              <span class="gr-diff label"> image/bmp </span>
-            </label>
-          `
-        );
-      });
-
-      test('renders added image', async () => {
-        const mockDiff: DiffInfo = {
-          meta_b: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 560},
-          intraline_status: 'OK',
-          change_type: 'ADDED',
-          diff_header: [
-            'diff --git a/carrot.jpg b/carrot.jpg',
-            'index 0000000..f9c2f2c 100644',
-            '--- /dev/null',
-            '+++ b/carrot.jpg',
-            'Binary files differ',
-          ],
-          content: [{skip: 66}],
-          binary: true,
-        };
-        element.revisionImage = mockFile2;
-        element.diff = mockDiff;
-
-        await waitForEventOnce(element, 'render');
-        const imageDiffSection = queryAndAssert(element, 'tbody.image-diff');
-        const leftImage = query(imageDiffSection, 'td.left img');
-        const rightImage = queryAndAssert(imageDiffSection, 'td.right img');
-        assert.isNotOk(leftImage);
-        assert.dom.equal(
-          rightImage,
-          /* HTML */ `
-            <img
-              class="gr-diff right"
-              src="data:image/bmp;base64,${mockFile2.body}"
-            />
-          `
-        );
-      });
-
-      test('renders removed image', async () => {
-        const mockDiff: DiffInfo = {
-          meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 560},
-          intraline_status: 'OK',
-          change_type: 'DELETED',
-          diff_header: [
-            'diff --git a/carrot.jpg b/carrot.jpg',
-            'index f9c2f2c..0000000 100644',
-            '--- a/carrot.jpg',
-            '+++ /dev/null',
-            'Binary files differ',
-          ],
-          content: [{skip: 66}],
-          binary: true,
-        };
-        element.baseImage = mockFile1;
-        element.diff = mockDiff;
-
-        await waitForEventOnce(element, 'render');
-        const imageDiffSection = queryAndAssert(element, 'tbody.image-diff');
-        const leftImage = queryAndAssert(imageDiffSection, 'td.left img');
-        const rightImage = query(imageDiffSection, 'td.right img');
-        assert.isNotOk(rightImage);
-        assert.dom.equal(
-          leftImage,
-          /* HTML */ `
-            <img
-              class="gr-diff left"
-              src="data:image/bmp;base64,${mockFile1.body}"
-            />
-          `
-        );
-      });
-
-      test('does not render disallowed image type', async () => {
-        const mockDiff: DiffInfo = {
-          meta_a: {
-            name: 'carrot.jpg',
-            content_type: 'image/jpeg-evil',
-            lines: 560,
-          },
-          intraline_status: 'OK',
-          change_type: 'DELETED',
-          diff_header: [
-            'diff --git a/carrot.jpg b/carrot.jpg',
-            'index f9c2f2c..0000000 100644',
-            '--- a/carrot.jpg',
-            '+++ /dev/null',
-            'Binary files differ',
-          ],
-          content: [{skip: 66}],
-          binary: true,
-        };
-        mockFile1.type = 'image/jpeg-evil';
-        element.baseImage = mockFile1;
-        element.diff = mockDiff;
-
-        await waitForEventOnce(element, 'render');
-        const imageDiffSection = queryAndAssert(element, 'tbody.image-diff');
-        const leftImage = query(imageDiffSection, 'td.left img');
-        assert.isNotOk(leftImage);
-      });
-    });
-
-    test('handleTap lineNum', async () => {
-      const addDraftStub = sinon.stub(element, 'addDraftAtLine');
-      const el = document.createElement('div');
-      el.className = 'lineNum';
-      const promise = mockPromise();
-      el.addEventListener('click', e => {
-        element.handleTap(e);
-        assert.isTrue(addDraftStub.called);
-        assert.equal(addDraftStub.lastCall.args[0], el);
-        promise.resolve();
-      });
-      el.click();
-      await promise;
-    });
-
-    test('handleTap content', async () => {
-      const content = document.createElement('div');
-      const lineEl = document.createElement('div');
-      lineEl.className = 'lineNum';
-      const row = document.createElement('div');
-      row.appendChild(lineEl);
-      row.appendChild(content);
-
-      const selectStub = sinon.stub(element, 'selectLine');
-
-      content.className = 'content';
-      const promise = mockPromise();
-      content.addEventListener('click', e => {
-        element.handleTap(e);
-        assert.isTrue(selectStub.called);
-        assert.equal(selectStub.lastCall.args[0], lineEl);
-        promise.resolve();
-      });
-      content.click();
-      await promise;
-    });
-
-    suite('getCursorStops', () => {
-      async function setupDiff() {
-        element.diff = createDiff();
-        element.prefs = {
-          context: 10,
-          tab_size: 8,
-          font_size: 12,
-          line_length: 100,
-          cursor_blink_rate: 0,
-          line_wrapping: false,
-
-          show_line_endings: true,
-          show_tabs: true,
-          show_whitespace_errors: true,
-          syntax_highlighting: true,
-          ignore_whitespace: 'IGNORE_NONE',
-        };
-        await element.updateComplete;
-        element.renderDiffTable();
-      }
-
-      test('returns [] when hidden and noAutoRender', async () => {
-        element.noAutoRender = true;
-        await setupDiff();
-        element.loading = false;
-        await element.updateComplete;
-        element.hidden = true;
-        await element.updateComplete;
-        assert.equal(element.getCursorStops().length, 0);
-      });
-
-      test('returns one stop per line and one for the file row', async () => {
-        await setupDiff();
-        element.loading = false;
-        await element.updateComplete;
-        const ROWS = 48;
-        const FILE_ROW = 1;
-        const LOST_ROW = 1;
-        assert.equal(
-          element.getCursorStops().length,
-          ROWS + FILE_ROW + LOST_ROW
-        );
-      });
-
-      test('returns an additional AbortStop when still loading', async () => {
-        await setupDiff();
-        element.loading = true;
-        await element.updateComplete;
-        const ROWS = 48;
-        const FILE_ROW = 1;
-        const LOST_ROW = 1;
-        const actual = element.getCursorStops();
-        assert.equal(actual.length, ROWS + FILE_ROW + LOST_ROW + 1);
-        assert.isTrue(actual[actual.length - 1] instanceof AbortStop);
-      });
-    });
-  });
-
-  suite('logged in', async () => {
-    let fakeLineEl: HTMLElement;
-    setup(async () => {
-      element.loggedIn = true;
-
-      fakeLineEl = {
-        getAttribute: sinon.stub().returns(42),
-        classList: {
-          contains: sinon.stub().returns(true),
-        },
-      } as unknown as HTMLElement;
-      await element.updateComplete;
-    });
-
-    test('addDraftAtLine', () => {
-      sinon.stub(element, 'selectLine');
-      const createCommentStub = sinon.stub(element, 'createComment');
-      element.addDraftAtLine(fakeLineEl);
-      assert.isTrue(createCommentStub.calledWithExactly(fakeLineEl, 42));
-    });
-
-    test('adds long range comment hint', async () => {
-      const range = {
-        start_line: 1,
-        end_line: 12,
-        start_character: 0,
-        end_character: 0,
-      };
-      const threadEl = document.createElement('div');
-      threadEl.className = 'comment-thread';
-      threadEl.setAttribute('diff-side', 'right');
-      threadEl.setAttribute('line-num', '1');
-      threadEl.setAttribute('range', JSON.stringify(range));
-      threadEl.setAttribute('slot', 'right-1');
-      const content = [
-        {
-          a: ['asdf'],
-        },
-        {
-          ab: Array(13).fill('text'),
-        },
-      ];
-      await setupSampleDiff({content});
-
-      element.appendChild(threadEl);
-
-      const hint = await waitQueryAndAssert<GrRangedCommentHint>(
-        element,
-        'gr-ranged-comment-hint'
-      );
-      assert.deepEqual(hint.range, range);
-    });
-
-    test('no duplicate range hint for same thread', async () => {
-      const range = {
-        start_line: 1,
-        end_line: 12,
-        start_character: 0,
-        end_character: 0,
-      };
-      const threadEl = document.createElement('div');
-      threadEl.className = 'comment-thread';
-      threadEl.setAttribute('diff-side', 'right');
-      threadEl.setAttribute('line-num', '1');
-      threadEl.setAttribute('range', JSON.stringify(range));
-      threadEl.setAttribute('slot', 'right-1');
-      const firstHint = document.createElement('gr-ranged-comment-hint');
-      firstHint.range = range;
-      firstHint.setAttribute('slot', 'right-1');
-      const content = [
-        {
-          a: ['asdf'],
-        },
-        {
-          ab: Array(13).fill('text'),
-        },
-      ];
-      await setupSampleDiff({content});
-
-      element.appendChild(firstHint);
-      element.appendChild(threadEl);
-
-      assert.equal(
-        element.querySelectorAll('gr-ranged-comment-hint').length,
-        1
-      );
-    });
-
-    test('removes long range comment hint when comment is discarded', async () => {
-      const range = {
-        start_line: 1,
-        end_line: 7,
-        start_character: 0,
-        end_character: 0,
-      };
-      const threadEl = document.createElement('div');
-      threadEl.className = 'comment-thread';
-      threadEl.setAttribute('diff-side', 'right');
-      threadEl.setAttribute('line-num', '1');
-      threadEl.setAttribute('range', JSON.stringify(range));
-      threadEl.setAttribute('slot', 'right-1');
-      const content = [
-        {
-          ab: Array(8).fill('text'),
-        },
-      ];
-      await setupSampleDiff({content});
-
-      element.appendChild(threadEl);
-      await waitUntil(() => element.commentRanges.length === 1);
-
-      threadEl.remove();
-      await waitUntil(() => element.commentRanges.length === 0);
-
-      assert.isEmpty(element.querySelectorAll('gr-ranged-comment-hint'));
-    });
-
-    suite('change in preferences', () => {
-      setup(async () => {
-        element.diff = {
-          meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 66},
-          meta_b: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 560},
-          diff_header: [],
-          intraline_status: 'OK',
-          change_type: 'MODIFIED',
-          content: [{skip: 66}],
-        };
-        await element.updateComplete;
-        await element.renderDiffTableTask?.flush();
-      });
-
-      test('change in preferences re-renders diff', async () => {
-        const stub = sinon.stub(element, 'renderDiffTable');
-        element.prefs = {
-          ...MINIMAL_PREFS,
-        };
-        await element.updateComplete;
-        await element.renderDiffTableTask?.flush();
-        assert.isTrue(stub.called);
-      });
-
-      test('adding/removing property in preferences re-renders diff', async () => {
-        const stub = sinon.stub(element, 'renderDiffTable');
-        const newPrefs1: DiffPreferencesInfo = {
-          ...MINIMAL_PREFS,
-          line_wrapping: true,
-        };
-        element.prefs = newPrefs1;
-        await element.updateComplete;
-        await element.renderDiffTableTask?.flush();
-        assert.isTrue(stub.called);
-        stub.reset();
-
-        const newPrefs2 = {...newPrefs1};
-        delete newPrefs2.line_wrapping;
-        element.prefs = newPrefs2;
-        await element.updateComplete;
-        await element.renderDiffTableTask?.flush();
-        assert.isTrue(stub.called);
-      });
-
-      test(
-        'change in preferences does not re-renders diff with ' +
-          'noRenderOnPrefsChange',
-        async () => {
-          const stub = sinon.stub(element, 'renderDiffTable');
-          element.noRenderOnPrefsChange = true;
-          element.prefs = {
-            ...MINIMAL_PREFS,
-            context: 12,
-          };
-          await element.updateComplete;
-          await element.renderDiffTableTask?.flush();
-          assert.isFalse(stub.called);
-        }
-      );
-    });
-  });
-
-  suite('diff header', () => {
-    setup(async () => {
-      element.diff = {
-        meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 66},
-        meta_b: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 560},
-        diff_header: [],
-        intraline_status: 'OK',
-        change_type: 'MODIFIED',
-        content: [{skip: 66}],
-      };
-      await element.updateComplete;
-    });
-
-    test('hidden', async () => {
-      assert.equal(element.computeDiffHeaderItems().length, 0);
-      element.diff?.diff_header?.push('diff --git a/test.jpg b/test.jpg');
-      assert.equal(element.computeDiffHeaderItems().length, 0);
-      element.diff?.diff_header?.push('index 2adc47d..f9c2f2c 100644');
-      assert.equal(element.computeDiffHeaderItems().length, 0);
-      element.diff?.diff_header?.push('--- a/test.jpg');
-      assert.equal(element.computeDiffHeaderItems().length, 0);
-      element.diff?.diff_header?.push('+++ b/test.jpg');
-      assert.equal(element.computeDiffHeaderItems().length, 0);
-      element.diff?.diff_header?.push('test');
-      assert.equal(element.computeDiffHeaderItems().length, 1);
-      element.requestUpdate('diff');
-      await element.updateComplete;
-
-      const header = queryAndAssert(element, '#diffHeader');
-      assert.equal(header.textContent?.trim(), 'test');
-    });
-
-    test('binary files', () => {
-      element.diff!.binary = true;
-      assert.equal(element.computeDiffHeaderItems().length, 0);
-      element.diff?.diff_header?.push('diff --git a/test.jpg b/test.jpg');
-      assert.equal(element.computeDiffHeaderItems().length, 0);
-      element.diff?.diff_header?.push('test');
-      assert.equal(element.computeDiffHeaderItems().length, 1);
-      element.diff?.diff_header?.push('Binary files differ');
-      assert.equal(element.computeDiffHeaderItems().length, 1);
-    });
-  });
-
-  suite('safety and bypass', () => {
-    let renderStub: sinon.SinonStub;
-
-    setup(async () => {
-      renderStub = sinon.stub(element.diffBuilder, 'render').callsFake(() => {
-        assertIsDefined(element.diffTable);
-        const diffTable = element.diffTable;
-        diffTable.dispatchEvent(
-          new CustomEvent('render', {bubbles: true, composed: true})
-        );
-        return Promise.resolve();
-      });
-      sinon.stub(element, 'getDiffLength').returns(10000);
-      element.diff = createDiff();
-      element.noRenderOnPrefsChange = true;
-      await element.updateComplete;
-    });
-
-    test('large render w/ context = 10', async () => {
-      element.prefs = {...MINIMAL_PREFS, context: 10};
-      element.renderDiffTable();
-      await waitForEventOnce(element, 'render');
-
-      assert.isTrue(renderStub.called);
-      assert.isFalse(element.showWarning);
-    });
-
-    test('large render w/ whole file and bypass', async () => {
-      element.prefs = {...MINIMAL_PREFS, context: -1};
-      element.safetyBypass = 10;
-      element.renderDiffTable();
-      await waitForEventOnce(element, 'render');
-
-      assert.isTrue(renderStub.called);
-      assert.isFalse(element.showWarning);
-    });
-
-    test('large render w/ whole file and no bypass', async () => {
-      element.prefs = {...MINIMAL_PREFS, context: -1};
-      element.renderDiffTable();
-      await waitForEventOnce(element, 'render');
-
-      assert.isFalse(renderStub.called);
-      assert.isTrue(element.showWarning);
-    });
-
-    test('toggles expand context using bypass', async () => {
-      element.prefs = {...MINIMAL_PREFS, context: 3};
-
-      element.toggleAllContext();
-      element.renderDiffTable();
-      await element.updateComplete;
-
-      assert.equal(element.prefs.context, 3);
-      assert.equal(element.safetyBypass, -1);
-      assert.equal(element.diffBuilder.prefs.context, -1);
-    });
-
-    test('toggles collapse context from bypass', async () => {
-      element.prefs = {...MINIMAL_PREFS, context: 3};
-      element.safetyBypass = -1;
-
-      element.toggleAllContext();
-      element.renderDiffTable();
-      await element.updateComplete;
-
-      assert.equal(element.prefs.context, 3);
-      assert.isNull(element.safetyBypass);
-      assert.equal(element.diffBuilder.prefs.context, 3);
-    });
-
-    test('toggles collapse context from pref using default', async () => {
-      element.prefs = {...MINIMAL_PREFS, context: -1};
-
-      element.toggleAllContext();
-      element.renderDiffTable();
-      await element.updateComplete;
-
-      assert.equal(element.prefs.context, -1);
-      assert.equal(element.safetyBypass, 10);
-      assert.equal(element.diffBuilder.prefs.context, 10);
-    });
-  });
-
-  suite('blame', () => {
-    test('unsetting', async () => {
-      element.blame = [];
-      const setBlameSpy = sinon.spy(element.diffBuilder, 'setBlame');
-      element.classList.add('showBlame');
-      element.blame = null;
-      await element.updateComplete;
-      assert.isTrue(setBlameSpy.calledWithExactly(null));
-      assert.isFalse(element.classList.contains('showBlame'));
-    });
-
-    test('setting', async () => {
-      element.blame = [
-        {
-          author: 'test-author',
-          time: 12345,
-          commit_msg: '',
-          id: 'commit id',
-          ranges: [{start: 1, end: 2}],
-        },
-      ];
-      await element.updateComplete;
-      assert.isTrue(element.classList.contains('showBlame'));
-    });
-  });
-
-  suite('trailing newline warnings', () => {
-    const NO_NEWLINE_LEFT = 'No newline at end of left file.';
-    const NO_NEWLINE_RIGHT = 'No newline at end of right file.';
-
-    const getWarning = (element: GrDiff) => {
-      const warningElement = query(element, '.newlineWarning');
-      return warningElement?.textContent ?? '';
-    };
-
-    setup(async () => {
-      element.showNewlineWarningLeft = false;
-      element.showNewlineWarningRight = false;
-      await element.updateComplete;
-    });
-
-    test('shows combined warning if both sides set to warn', async () => {
-      element.showNewlineWarningLeft = true;
-      element.showNewlineWarningRight = true;
-      await element.updateComplete;
-      assert.include(
-        getWarning(element),
-        NO_NEWLINE_LEFT + ' \u2014 ' + NO_NEWLINE_RIGHT
-      ); // \u2014 - '—'
-    });
-
-    suite('showNewlineWarningLeft', () => {
-      test('show warning if true', async () => {
-        element.showNewlineWarningLeft = true;
-        await element.updateComplete;
-        assert.include(getWarning(element), NO_NEWLINE_LEFT);
-      });
-
-      test('hide warning if false', async () => {
-        element.showNewlineWarningLeft = false;
-        await element.updateComplete;
-        assert.notInclude(getWarning(element), NO_NEWLINE_LEFT);
-      });
-    });
-
-    suite('showNewlineWarningRight', () => {
-      test('show warning if true', async () => {
-        element.showNewlineWarningRight = true;
-        await element.updateComplete;
-        assert.include(getWarning(element), NO_NEWLINE_RIGHT);
-      });
-
-      test('hide warning if false', async () => {
-        element.showNewlineWarningRight = false;
-        await element.updateComplete;
-        assert.notInclude(getWarning(element), NO_NEWLINE_RIGHT);
-      });
-    });
-  });
-
-  suite('key locations', () => {
-    let renderStub: sinon.SinonStub;
-
-    setup(async () => {
-      element.prefs = {...MINIMAL_PREFS};
-      element.diff = createDiff();
-      renderStub = sinon.stub(element.diffBuilder, 'render');
-      await element.updateComplete;
-    });
-
-    test('lineOfInterest is a key location', () => {
-      element.lineOfInterest = {lineNum: 789, side: Side.LEFT};
-      element.renderDiffTable();
-      assert.isTrue(renderStub.called);
-      assert.deepEqual(renderStub.lastCall.args[0], {
-        left: {789: true},
-        right: {},
-      });
-    });
-
-    test('line comments are key locations', async () => {
-      const threadEl = document.createElement('div');
-      threadEl.className = 'comment-thread';
-      threadEl.setAttribute('diff-side', 'right');
-      threadEl.setAttribute('line-num', '3');
-      element.appendChild(threadEl);
-      await element.updateComplete;
-
-      element.renderDiffTable();
-      assert.isTrue(renderStub.called);
-      assert.deepEqual(renderStub.lastCall.args[0], {
-        left: {},
-        right: {3: true},
-      });
-    });
-
-    test('file comments are key locations', async () => {
-      const threadEl = document.createElement('div');
-      threadEl.className = 'comment-thread';
-      threadEl.setAttribute('diff-side', 'left');
-      element.appendChild(threadEl);
-      await element.updateComplete;
-
-      element.renderDiffTable();
-      assert.isTrue(renderStub.called);
-      assert.deepEqual(renderStub.lastCall.args[0], {
-        left: {FILE: true},
-        right: {},
-      });
-    });
-  });
-  const setupSampleDiff = async function (params: {
-    content: DiffContent[];
-    ignore_whitespace?: IgnoreWhitespaceType;
-    binary?: boolean;
-  }) {
-    const {ignore_whitespace, content} = params;
-    // binary can't be undefined, use false if not set
-    const binary = params.binary || false;
-    element.prefs = {
-      ignore_whitespace: ignore_whitespace || 'IGNORE_ALL',
-      context: 10,
-      cursor_blink_rate: 0,
-      font_size: 12,
-
-      line_length: 100,
-      line_wrapping: false,
-      show_line_endings: true,
-      show_tabs: true,
-      show_whitespace_errors: true,
-      syntax_highlighting: true,
-      tab_size: 8,
-    };
-    element.diff = {
-      intraline_status: 'OK',
-      change_type: 'MODIFIED',
-      diff_header: [
-        'diff --git a/carrot.js b/carrot.js',
-        'index 2adc47d..f9c2f2c 100644',
-        '--- a/carrot.js',
-        '+++ b/carrot.jjs',
-        'file differ',
-      ],
-      content,
-      binary,
-    };
-    await element.updateComplete;
-    await element.renderDiffTableTask;
-  };
-
-  test('clear diff table content as soon as diff changes', async () => {
-    const content = [
-      {
-        a: ['all work and no play make andybons a dull boy'],
-      },
-      {
-        b: ['Non eram nescius, Brute, cum, quae summis ingeniis '],
-      },
-    ];
-    function diffTableHasContent() {
-      assertIsDefined(element.diffTable);
-      const diffTable = element.diffTable;
-      return diffTable.innerText.includes(content[0].a?.[0] ?? '');
-    }
-    await setupSampleDiff({content});
-    await waitUntil(diffTableHasContent);
-    element.diff = {...element.diff!};
-    await element.updateComplete;
-    // immediately cleaned up
-    assertIsDefined(element.diffTable);
-    const diffTable = element.diffTable;
-    assert.equal(diffTable.innerHTML, '');
-    element.renderDiffTable();
-    await element.updateComplete;
-    // rendered again
-    await waitUntil(diffTableHasContent);
-  });
-
-  suite('selection test', () => {
-    test('user-select set correctly on side-by-side view', async () => {
-      const content = [
-        {
-          a: ['all work and no play make andybons a dull boy'],
-          b: ['elgoog elgoog elgoog'],
-        },
-        {
-          ab: [
-            'Non eram nescius, Brute, cum, quae summis ingeniis ',
-            'exquisitaque doctrina philosophi Graeco sermone tractavissent',
-          ],
-        },
-      ];
-      await setupSampleDiff({content});
-      await waitEventLoop();
-
-      const diffLine = queryAll<HTMLElement>(element, '.contentText')[2];
-      assert.equal(getComputedStyle(diffLine).userSelect, 'none');
-      mouseDown(diffLine);
-      assert.equal(getComputedStyle(diffLine).userSelect, 'text');
-    });
-
-    test('user-select set correctly on unified view', async () => {
-      const content = [
-        {
-          a: ['all work and no play make andybons a dull boy'],
-          b: ['elgoog elgoog elgoog'],
-        },
-        {
-          ab: [
-            'Non eram nescius, Brute, cum, quae summis ingeniis ',
-            'exquisitaque doctrina philosophi Graeco sermone tractavissent',
-          ],
-        },
-      ];
-      await setupSampleDiff({content});
-      element.viewMode = DiffViewMode.UNIFIED;
-      await element.updateComplete;
-      const diffLine = queryAll<HTMLElement>(element, '.contentText')[2];
-      assert.equal(getComputedStyle(diffLine).userSelect, 'none');
-      mouseDown(diffLine);
-      assert.equal(getComputedStyle(diffLine).userSelect, 'text');
-    });
-  });
-
-  suite('whitespace changes only message', () => {
-    test('show the message if ignore_whitespace is criteria matches', async () => {
-      await setupSampleDiff({content: [{skip: 100}]});
-      element.loading = false;
-      assert.isTrue(element.showNoChangeMessage());
-    });
-
-    test('do not show the message for binary files', async () => {
-      await setupSampleDiff({content: [{skip: 100}], binary: true});
-      element.loading = false;
-      assert.isFalse(element.showNoChangeMessage());
-    });
-
-    test('do not show the message if still loading', async () => {
-      await setupSampleDiff({content: [{skip: 100}]});
-      element.loading = true;
-      assert.isFalse(element.showNoChangeMessage());
-    });
-
-    test('do not show the message if contains valid changes', async () => {
-      const content = [
-        {
-          a: ['all work and no play make andybons a dull boy'],
-          b: ['elgoog elgoog elgoog'],
-        },
-        {
-          ab: [
-            'Non eram nescius, Brute, cum, quae summis ingeniis ',
-            'exquisitaque doctrina philosophi Graeco sermone tractavissent',
-          ],
-        },
-      ];
-      await setupSampleDiff({content});
-      element.loading = false;
-      assert.equal(element.diffLength, 3);
-      assert.isFalse(element.showNoChangeMessage());
-    });
-
-    test('do not show message if ignore whitespace is disabled', async () => {
-      const content = [
-        {
-          a: ['all work and no play make andybons a dull boy'],
-          b: ['elgoog elgoog elgoog'],
-        },
-        {
-          ab: [
-            'Non eram nescius, Brute, cum, quae summis ingeniis ',
-            'exquisitaque doctrina philosophi Graeco sermone tractavissent',
-          ],
-        },
-      ];
-      await setupSampleDiff({ignore_whitespace: 'IGNORE_NONE', content});
-      element.loading = false;
-      assert.isFalse(element.showNoChangeMessage());
-    });
-  });
-
-  test('getDiffLength', () => {
-    const diff = createDiff();
-    assert.equal(element.getDiffLength(diff), 52);
-  });
-});
diff --git a/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls-section.ts b/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls-section.ts
index e7ae8a4..394d09b 100644
--- a/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls-section.ts
+++ b/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls-section.ts
@@ -8,7 +8,7 @@
 import {property, state} from 'lit/decorators.js';
 import {DiffInfo, DiffViewMode, RenderPreferences} from '../../../api/diff';
 import {GrDiffGroup, GrDiffGroupType} from '../gr-diff/gr-diff-group';
-import {diffClasses, isNewDiff} from '../gr-diff/gr-diff-utils';
+import {diffClasses} from '../gr-diff/gr-diff-utils';
 import {getShowConfig} from './gr-context-controls';
 import {ifDefined} from 'lit/directives/if-defined.js';
 import {when} from 'lit/directives/when.js';
@@ -140,17 +140,10 @@
   }
 }
 
-// TODO(newdiff-cleanup): Remove once newdiff migration is completed.
-if (isNewDiff()) {
-  customElements.define(
-    'gr-context-controls-section',
-    GrContextControlsSection
-  );
-}
+customElements.define('gr-context-controls-section', GrContextControlsSection);
 
 declare global {
   interface HTMLElementTagNameMap {
-    // TODO(newdiff-cleanup): Replace once newdiff migration is completed.
-    'gr-context-controls-section': LitElement;
+    'gr-context-controls-section': GrContextControlsSection;
   }
 }
diff --git a/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls.ts b/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls.ts
index b2c0fcb..e889b90 100644
--- a/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls.ts
+++ b/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls.ts
@@ -32,7 +32,6 @@
 } from '../../../api/diff';
 
 import {GrDiffGroup, hideInContextControl} from '../gr-diff/gr-diff-group';
-import {isNewDiff} from '../gr-diff/gr-diff-utils';
 
 declare global {
   interface HTMLElementEventMap {
@@ -527,14 +526,10 @@
   }
 }
 
-// TODO(newdiff-cleanup): Remove once newdiff migration is completed.
-if (isNewDiff()) {
-  customElements.define('gr-context-controls', GrContextControls);
-}
+customElements.define('gr-context-controls', GrContextControls);
 
 declare global {
   interface HTMLElementTagNameMap {
-    // TODO(newdiff-cleanup): Replace once newdiff migration is completed.
-    'gr-context-controls': LitElement;
+    'gr-context-controls': GrContextControls;
   }
 }
diff --git a/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls_test.ts b/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls_test.ts
index 7f5827c..215dc88 100644
--- a/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls_test.ts
+++ b/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls_test.ts
@@ -23,10 +23,7 @@
   let element: GrContextControls;
 
   setup(async () => {
-    // TODO(newdiff-cleanup): Remove cast when newdiff migration is complete.
-    element = document.createElement(
-      'gr-context-controls'
-    ) as GrContextControls;
+    element = document.createElement('gr-context-controls');
     element.diff = {content: []} as any as DiffInfo;
     element.renderPreferences = {};
     const div = await fixture(html`<div></div>`);
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder-image.ts b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder-image.ts
index fd3b975..9eb1e14 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder-image.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder-image.ts
@@ -8,7 +8,6 @@
 import '../gr-diff-image-viewer/gr-image-viewer';
 import {html, LitElement, nothing} from 'lit';
 import {property, query, state} from 'lit/decorators.js';
-import {isNewDiff} from '../gr-diff/gr-diff-utils';
 
 // MIME types for images we allow showing. Do not include SVG, it can contain
 // arbitrary JavaScript.
@@ -201,16 +200,12 @@
     : '';
 }
 
-// TODO(newdiff-cleanup): Remove once newdiff migration is completed.
-if (isNewDiff()) {
-  customElements.define('gr-diff-image-new', GrDiffImageNew);
-  customElements.define('gr-diff-image-old', GrDiffImageOld);
-}
+customElements.define('gr-diff-image-new', GrDiffImageNew);
+customElements.define('gr-diff-image-old', GrDiffImageOld);
 
 declare global {
   interface HTMLElementTagNameMap {
-    // TODO(newdiff-cleanup): Replace once newdiff migration is completed.
-    'gr-diff-image-new': LitElement;
-    'gr-diff-image-old': LitElement;
+    'gr-diff-image-new': GrDiffImageNew;
+    'gr-diff-image-old': GrDiffImageOld;
   }
 }
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-row.ts b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-row.ts
index da84b34..8f71936 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-row.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-row.ts
@@ -26,7 +26,6 @@
   diffClasses,
   GrDiffCommentThread,
   isLongCommentRange,
-  isNewDiff,
   isResponsive,
 } from '../gr-diff/gr-diff-utils';
 import {resolve} from '../../../models/dependency';
@@ -579,14 +578,10 @@
   }
 }
 
-// TODO(newdiff-cleanup): Remove once newdiff migration is completed.
-if (isNewDiff()) {
-  customElements.define('gr-diff-row', GrDiffRow);
-}
+customElements.define('gr-diff-row', GrDiffRow);
 
 declare global {
   interface HTMLElementTagNameMap {
-    // TODO(newdiff-cleanup): Replace once newdiff migration is completed.
-    'gr-diff-row': LitElement;
+    'gr-diff-row': GrDiffRow;
   }
 }
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-section.ts b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-section.ts
index 325f902..4dd580f 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-section.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-section.ts
@@ -15,11 +15,7 @@
   DiffPreferencesInfo,
 } from '../../../api/diff';
 import {GrDiffGroup, GrDiffGroupType} from '../gr-diff/gr-diff-group';
-import {
-  isNewDiff,
-  diffClasses,
-  getResponsiveMode,
-} from '../gr-diff/gr-diff-utils';
+import {diffClasses, getResponsiveMode} from '../gr-diff/gr-diff-utils';
 import {GrDiffRow} from './gr-diff-row';
 import '../gr-context-controls/gr-context-controls-section';
 import '../gr-context-controls/gr-context-controls';
@@ -297,14 +293,10 @@
   }
 }
 
-// TODO(newdiff-cleanup): Remove once newdiff migration is completed.
-if (isNewDiff()) {
-  customElements.define('gr-diff-section', GrDiffSection);
-}
+customElements.define('gr-diff-section', GrDiffSection);
 
 declare global {
   interface HTMLElementTagNameMap {
-    // TODO(newdiff-cleanup): Replace once newdiff migration is completed.
-    'gr-diff-section': LitElement;
+    'gr-diff-section': GrDiffSection;
   }
 }
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-text.ts b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-text.ts
index 2acedc8..5161b18 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-text.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-text.ts
@@ -6,7 +6,7 @@
 import {LitElement, html, TemplateResult} from 'lit';
 import {property} from 'lit/decorators.js';
 import {styleMap} from 'lit/directives/style-map.js';
-import {isNewDiff, diffClasses} from '../gr-diff/gr-diff-utils';
+import {diffClasses} from '../gr-diff/gr-diff-utils';
 
 const SURROGATE_PAIR = /[\uD800-\uDBFF][\uDC00-\uDFFF]/;
 
@@ -144,14 +144,10 @@
   }
 }
 
-// TODO(newdiff-cleanup): Remove once newdiff migration is completed.
-if (isNewDiff()) {
-  customElements.define('gr-diff-text', GrDiffText);
-}
+customElements.define('gr-diff-text', GrDiffText);
 
 declare global {
   interface HTMLElementTagNameMap {
-    // TODO(newdiff-cleanup): Replace once newdiff migration is completed.
-    'gr-diff-text': LitElement;
+    'gr-diff-text': GrDiffText;
   }
 }
diff --git a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-element.ts b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-element.ts
index 352d5db..3ea3ada 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-element.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-element.ts
@@ -16,7 +16,6 @@
 import '../gr-diff-builder/gr-diff-row';
 import {
   isResponsive,
-  isNewDiff,
   FullContext,
   diffClasses,
   FULL_CONTEXT,
@@ -186,7 +185,6 @@
 
   private renderContainer() {
     const cssClasses = {
-      newDiff: true,
       diffContainer: true,
       unified: this.viewMode === DiffViewMode.UNIFIED,
       sideBySide: this.viewMode === DiffViewMode.SIDE_BY_SIDE,
@@ -411,10 +409,7 @@
   return prefs.font_size * 4;
 }
 
-// TODO(newdiff-cleanup): Remove once newdiff migration is completed.
-if (isNewDiff()) {
-  customElements.define('gr-diff-element', GrDiffElement);
-}
+customElements.define('gr-diff-element', GrDiffElement);
 
 declare global {
   interface HTMLElementTagNameMap {
diff --git a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-element_test.ts b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-element_test.ts
index 8cc5324..c6194c5 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-element_test.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-element_test.ts
@@ -57,7 +57,7 @@
       assert.lightDom.equal(
         element,
         /* HTML */ `
-          <div class="diffContainer newDiff sideBySide">
+          <div class="diffContainer sideBySide">
             <table id="diffTable">
               <colgroup>
                 <col class="blame gr-diff" />
@@ -85,7 +85,7 @@
       assert.lightDom.equal(
         element,
         /* HTML */ `
-          <div class="diffContainer newDiff unified">
+          <div class="diffContainer unified">
             <table id="diffTable">
               <colgroup>
                 <col class="blame gr-diff" />
@@ -1319,7 +1319,7 @@
       assert.lightDom.equal(
         element,
         /* HTML */ `
-          <div class="diffContainer newDiff sideBySide">
+          <div class="diffContainer sideBySide">
             <table id="diffTable">
               <colgroup>
                 <col class="blame gr-diff" />
@@ -2935,7 +2935,7 @@
         assert.lightDom.equal(
           element,
           /* HTML */ `
-            <div class="diffContainer newDiff sideBySide">
+            <div class="diffContainer sideBySide">
               <gr-diff-section class="left-FILE right-FILE"> </gr-diff-section>
               <gr-diff-row class="left-FILE right-FILE"> </gr-diff-row>
               <table id="diffTable">
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 e5a5e65..f2f85af 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
@@ -462,10 +462,7 @@
     color: var(--link-color);
     padding: var(--spacing-m) 0 var(--spacing-m) 48px;
   }
-  /* for new diff */
-  gr-diff-element,
-  /* for old diff, TODO: remove */
-  #diffTable {
+  gr-diff-element {
     /* for gr-selection-action-box positioning */
     position: relative;
   }
diff --git a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-utils.ts b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-utils.ts
index 7e30581..0a4d5b9 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-utils.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-utils.ts
@@ -40,12 +40,6 @@
  */
 export const REGEX_TAB_OR_SURROGATE_PAIR = /\t|[\uD800-\uDBFF][\uDC00-\uDFFF]/;
 
-// TODO(newdiff-cleanup): Remove once newdiff migration is completed.
-export function isNewDiff() {
-  const flags = new Set(window.ENABLED_EXPERIMENTS ?? []);
-  return flags.has('UiFeature__new_diff');
-}
-
 export function getResponsiveMode(
   prefs?: DiffPreferencesInfo,
   renderPrefs?: RenderPreferences
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 58cad19..5738cb7 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts
@@ -20,7 +20,6 @@
   isThreadEl,
   getResponsiveMode,
   isResponsive,
-  isNewDiff,
   getSideByLineEl,
   compareComments,
   getDataFromCommentThreadEl,
@@ -47,6 +46,7 @@
   DisplayLine,
   LineNumber,
   ContentLoadNeededEventDetail,
+  DiffContextExpandedExternalDetail,
 } from '../../../api/diff';
 import {isSafari, toggleClass} from '../../../utils/dom-util';
 import {assertIsDefined} from '../../../utils/common-util';
@@ -490,9 +490,6 @@
     this.commentThreadRedispatcher(e.target, 'comment-thread-mouseleave');
   };
 
-  /** TODO: Can be removed when diff-old is gone. */
-  cancel() {}
-
   getCursorStops(): Array<HTMLElement | AbortStop> {
     if (this.hidden && this.noAutoRender) return [];
 
@@ -697,9 +694,6 @@
     this.rangeLayer.updateRanges(ranges);
   }
 
-  /** TODO: Can be removed when diff-old is gone. */
-  clearDiffContent() {}
-
   // TODO: Migrate callers to just update prefs.context.
   toggleAllContext() {
     const current = this.diffModel.getState().showFullContext;
@@ -1017,15 +1011,11 @@
   }
 }
 
-// TODO(newdiff-cleanup): Remove once newdiff migration is completed.
-if (isNewDiff()) {
-  customElements.define('gr-diff', GrDiff);
-}
+customElements.define('gr-diff', GrDiff);
 
 declare global {
   interface HTMLElementTagNameMap {
-    // TODO(newdiff-cleanup): Replace once newdiff migration is completed.
-    'gr-diff': LitElement;
+    'gr-diff': GrDiff;
   }
   interface HTMLElementEventMap {
     'comment-thread-mouseenter': CustomEvent<GrDiffCommentThread>;
@@ -1042,6 +1032,7 @@
      * renders and for partial rerenders.
      */
     'render-content': CustomEvent<{}>;
+    'diff-context-expanded': CustomEvent<DiffContextExpandedExternalDetail>;
     'diff-context-expanded-internal-new': CustomEvent<DiffContextExpandedEventDetail>;
     'content-load-needed': CustomEvent<ContentLoadNeededEventDetail>;
   }
diff --git a/polygerrit-ui/app/embed/gr-diff.ts b/polygerrit-ui/app/embed/gr-diff.ts
index 02a153d..6de43ed 100644
--- a/polygerrit-ui/app/embed/gr-diff.ts
+++ b/polygerrit-ui/app/embed/gr-diff.ts
@@ -12,25 +12,20 @@
 // exposed by shared gr-diff component.
 import '../api/embed';
 import '../scripts/bundled-polymer';
-import './diff-old/gr-diff/gr-diff';
-import './diff-old/gr-diff-cursor/gr-diff-cursor';
 import './diff/gr-diff/gr-diff';
 import './diff/gr-diff-cursor/gr-diff-cursor';
 import {TokenHighlightLayer} from './diff/gr-diff-builder/token-highlight-layer';
-import {GrDiffCursor as GrDiffCursorOld} from './diff-old/gr-diff-cursor/gr-diff-cursor';
-import {GrDiffCursor as GrDiffCursorNew} from './diff/gr-diff-cursor/gr-diff-cursor';
-import {GrAnnotation as GrAnnotationOld} from './diff-old/gr-diff-highlight/gr-annotation';
-import {GrAnnotationImpl as GrAnnotationNew} from './diff/gr-diff-highlight/gr-annotation';
+import {GrDiffCursor} from './diff/gr-diff-cursor/gr-diff-cursor';
+import {GrAnnotationImpl as GrAnnotation} from './diff/gr-diff-highlight/gr-annotation';
 import {createDiffAppContext} from './gr-diff-app-context-init';
 import {injectAppContext} from '../services/app-context';
-import {isNewDiff} from './diff/gr-diff/gr-diff-utils';
 
 // Setup appContext for diff.
 // TODO (dmfilippov): find a better solution
 injectAppContext(createDiffAppContext());
 // Setup global variables for existing usages of this component
 window.grdiff = {
-  GrAnnotation: isNewDiff() ? GrAnnotationNew : GrAnnotationOld,
-  GrDiffCursor: isNewDiff() ? GrDiffCursorNew : GrDiffCursorOld,
+  GrAnnotation,
+  GrDiffCursor,
   TokenHighlightLayer,
 };
diff --git a/polygerrit-ui/web-test-runner.config.mjs b/polygerrit-ui/web-test-runner.config.mjs
index bd8d9ac..415571c 100644
--- a/polygerrit-ui/web-test-runner.config.mjs
+++ b/polygerrit-ui/web-test-runner.config.mjs
@@ -2,8 +2,7 @@
 import { defaultReporter, summaryReporter } from "@web/test-runner";
 import { visualRegressionPlugin } from "@web/test-runner-visual-regression/plugin";
 
-function testRunnerHtmlFactory(options) {
-  const setNewDiffExp = `<script type="text/javascript">window.ENABLED_EXPERIMENTS = ['UiFeature__new_diff'];</script>`;
+function testRunnerHtmlFactory() {
   return (testFramework) => `
     <!DOCTYPE html>
     <html>
@@ -15,7 +14,6 @@
           href="polygerrit-ui/app/styles/material-icons.css">
       </head>
       <body>
-        ${options.newDiff ? setNewDiffExp : ''}
         <script type="module" src="${testFramework}"></script>
       </body>
     </html>
@@ -26,34 +24,11 @@
 const config = {
   files: [
     "app/**/*_test.{ts,js}",
-    "!app/embed/diff/gr-context-controls/**/*_test.{ts,js}",
-    "!app/embed/diff/gr-diff/**/*_test.{ts,js}",
-    "!app/embed/diff/gr-diff-builder/**/*_test.{ts,js}",
-    "!app/embed/diff/gr-diff-cursor/**/*_test.{ts,js}",
-    "!app/embed/diff/gr-diff-highlight/**/*_test.{ts,js}",
-    "!app/embed/diff/gr-diff-model/**/*_test.{ts,js}",
-    "!app/embed/diff/gr-diff-processor/**/*_test.{ts,js}",
-    "!app/embed/diff/gr-diff-selection/**/*_test.{ts,js}",
     "!**/node_modules/**/*",
     ...(process.argv.includes("--run-screenshots")
       ? []
       : ["!app/**/*_screenshot_test.{ts,js}"]),
   ],
-  // TODO(newdiff-cleanup): Remove once newdiff migration is completed.
-  groups: [
-    {
-      name: "new-diff",
-      files: [
-        "app/embed/diff/**/*_test.{ts,js}",
-        "app/elements/change/gr-file-list/gr-file-list_test.{ts,js}",
-        "app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.{ts,js}",
-        "app/elements/diff/gr-diff-host/gr-diff-host_test.{ts,js}",
-        "app/elements/diff/gr-diff-view/gr-diff-view_test.{ts,js}",
-        "app/elements/shared/gr-comment-thread/gr-comment-thread_test.{ts,js}",
-      ],
-      testRunnerHtml: testRunnerHtmlFactory({newDiff: true}),
-    },
-  ],
   port: 9876,
   nodeResolve: true,
   testFramework: { config: { ui: "tdd", timeout: 5000 } },
@@ -85,6 +60,6 @@
       await next();
     },
   ],
-  testRunnerHtml: testRunnerHtmlFactory({newDiff: false}),
+  testRunnerHtml: testRunnerHtmlFactory(),
 };
 export default config;