Merge "Implement batch removal of reviewers in PostReview"
diff --git a/.bazelrc b/.bazelrc
index 6a3f06e..4d30086 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -13,6 +13,10 @@
 
 build --announce_rc
 
+# Workaround Bazel worker crash (remove after upgrading to 4.1.0)
+# https://github.com/bazelbuild/bazel/issues/13333
+build --experimental_worker_multiplex=false
+
 test --build_tests_only
 test --test_output=errors
 test --java_toolchain=//tools:error_prone_warnings_toolchain_java11
diff --git a/Documentation/logs.txt b/Documentation/logs.txt
index 6624366..ba370b1 100644
--- a/Documentation/logs.txt
+++ b/Documentation/logs.txt
@@ -51,6 +51,11 @@
 * `referer`: the `Referer` HTTP request header. This gives the site that
   the client reports having been referred from.
 * `client agent`: the client agent which sent the request.
+* `total_cpu`: total CPU time, CPU time in milliseconds to execute command.
+* `user_cpu`: user mode CPU time, CPU time in user mode in milliseconds to execute command.
+  CPU time in kernel mode is `total_cpu - user_cpu`.
+* `memory`: memory allocated in bytes to execute command. -1 if the JVM does
+  not support this metric.
 
 Example:
 ```
@@ -84,6 +89,11 @@
 * `wait`: command wait time, time in milliseconds the command waited for an execution thread.
 * `exec`: command execution time, time in milliseconds to execute the command.
 * `status`: status code. 0 means success, any other value is an error.
+* `total_cpu`: total CPU time, CPU time in milliseconds to execute command.
+* `user_cpu`: user mode CPU time, CPU time in user mode in milliseconds to execute command.
+  CPU time in kernel mode is `total_cpu - user_cpu`.
+* `memory`: memory allocated in bytes to execute command. -1 if the JVM does
+  not support this metric.
 
 The `git-upload-pack` command provides the following additional fields after the `exec`
 and before the `status` field. All times are in milliseconds. Fields are -1 if not available
diff --git a/Documentation/metrics.txt b/Documentation/metrics.txt
index 8931348..7a35d4d 100644
--- a/Documentation/metrics.txt
+++ b/Documentation/metrics.txt
@@ -50,6 +50,9 @@
 objects needing finalization.
 * `proc/jvm/gc/count`: Number of GCs.
 * `proc/jvm/gc/time`: Approximate accumulated GC elapsed time.
+* `proc/jvm/memory/pool/committed/<pool name>`: Committed amount of memory for pool.
+* `proc/jvm/memory/pool/max/<pool name>`: Maximum amount of memory for pool.
+* `proc/jvm/memory/pool/used/<pool name>`: Used amount of memory for pool.
 * `proc/jvm/thread/num_live`: Current live thread count.
 * `proc/jvm/thread/num_daemon_live`: Current live daemon threads count.
 * `proc/jvm/thread/num_peak_live`: Peak live thread count since the Java virtual machine started or peak was reset.
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index fb3e3ec..1581274 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -569,12 +569,10 @@
 populate ChangeInfo. If the SHA-1 is not reachable as a NoteDb state,
 status code 412 is returned.
 
-----
-
 [[get-meta-diff]]
 === Get Meta Diff
 --
-'GET /changes/link:#change-id[\{change-id\}]/meta_diff/?old=SHA-1&meta=SHA-1'
+'GET /changes/link:#change-id[\{change-id\}]/meta_diff?old=SHA-1&meta=SHA-1'
 --
 
 Retrieves the difference between two historical states of a change
@@ -631,7 +629,6 @@
 state, the status code 412 is returned. If the SHA-1 for `old`
 is not reachable, the difference between the change at state
 `meta` and an empty change is returned.
-----
 
 [[get-change-detail]]
 === Get Change Detail
diff --git a/Documentation/rest-api-config.txt b/Documentation/rest-api-config.txt
index a8d9b3d..6ca2b46 100644
--- a/Documentation/rest-api-config.txt
+++ b/Documentation/rest-api-config.txt
@@ -1941,6 +1941,9 @@
 |Field Name    ||Description
 |`has_avatars` |not set if `false`|
 Whether an avatar provider is registered.
+|`js_resource_paths`||
+A list of relative paths (strings). Each path points to a frontend plugin that
+should be loaded, e.g. `plugins/codemirror_editor/static/codemirror_editor.js`.
 |===========================
 
 [[receive-info]]
diff --git a/Documentation/user-search.txt b/Documentation/user-search.txt
index 377012a..a2dc31f 100644
--- a/Documentation/user-search.txt
+++ b/Documentation/user-search.txt
@@ -251,6 +251,16 @@
 often combined with 'branch:' and 'project:' operators to select
 all related changes in a series.
 
+[[inhashtag]]
+inhashtag:'HASHTAG'::
++
+Changes where any hashtag contains 'HASHTAG', using a full-text search.
++
+If 'HASHTAG' starts with `^` it matches hashtag names by regular
+expression patterns.  The
+link:http://www.brics.dk/automaton/[dk.brics.automaton
+library,role=external,window=_blank] is used for evaluation of such patterns.
+
 [[hashtag]]
 hashtag:'HASHTAG'::
 +
diff --git a/WORKSPACE b/WORKSPACE
index 8dad0f9..0d9b06a 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -66,8 +66,8 @@
 
 http_archive(
     name = "build_bazel_rules_nodejs",
-    sha256 = "dd7ea7efda7655c218ca707f55c3e1b9c68055a70c31a98f264b3445bc8f4cb1",
-    urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/3.2.3/rules_nodejs-3.2.3.tar.gz"],
+    sha256 = "1134ec9b7baee008f1d54f0483049a97e53a57cd3913ec9d6db625549c98395a",
+    urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/3.4.0/rules_nodejs-3.4.0.tar.gz"],
 )
 
 # Golang support for PolyGerrit local dev server.
diff --git a/java/com/google/gerrit/entities/SubmitRecord.java b/java/com/google/gerrit/entities/SubmitRecord.java
index 1fd0864..9ebc671 100644
--- a/java/com/google/gerrit/entities/SubmitRecord.java
+++ b/java/com/google/gerrit/entities/SubmitRecord.java
@@ -53,7 +53,11 @@
     FORCED,
 
     /**
-     * An internal server error occurred preventing computation.
+     * A rule error caused by user misconfiguration.
+     *
+     * <p>This status should only be used to signal that the user has misconfigured the submit rule.
+     * In case plugins encounter server exceptions while evaluating the rule, they should throw a
+     * {@link RuntimeException} such as {@link IllegalStateException}.
      *
      * <p>Additional detail may be available in {@link SubmitRecord#errorMessage}.
      */
diff --git a/java/com/google/gerrit/extensions/common/PluginConfigInfo.java b/java/com/google/gerrit/extensions/common/PluginConfigInfo.java
index 13fc9ec..2d1d840 100644
--- a/java/com/google/gerrit/extensions/common/PluginConfigInfo.java
+++ b/java/com/google/gerrit/extensions/common/PluginConfigInfo.java
@@ -19,5 +19,4 @@
 public class PluginConfigInfo {
   public Boolean hasAvatars;
   public List<String> jsResourcePaths;
-  public List<String> htmlResourcePaths;
 }
diff --git a/java/com/google/gerrit/httpd/RequestMetricsFilter.java b/java/com/google/gerrit/httpd/RequestMetricsFilter.java
index c7a7540..c97b9ad 100644
--- a/java/com/google/gerrit/httpd/RequestMetricsFilter.java
+++ b/java/com/google/gerrit/httpd/RequestMetricsFilter.java
@@ -14,6 +14,8 @@
 
 package com.google.gerrit.httpd;
 
+import com.google.gerrit.metrics.proc.ThreadMXBeanFactory;
+import com.google.gerrit.metrics.proc.ThreadMXBeanInterface;
 import com.google.inject.Inject;
 import com.google.inject.Module;
 import com.google.inject.Singleton;
@@ -30,6 +32,8 @@
 
 @Singleton
 public class RequestMetricsFilter implements Filter {
+  public static final String METRICS_CONTEXT = "metrics-context";
+
   public static Module module() {
     return new ServletModule() {
       @Override
@@ -39,6 +43,36 @@
     };
   }
 
+  public static class Context {
+    private static final ThreadMXBeanInterface threadMxBean = ThreadMXBeanFactory.create();
+    private final long startedTotalCpu;
+    private final long startedUserCpu;
+    private final long startedMemory;
+
+    Context() {
+      startedTotalCpu = threadMxBean.getCurrentThreadCpuTime();
+      startedUserCpu = threadMxBean.getCurrentThreadUserTime();
+      startedMemory = threadMxBean.getCurrentThreadAllocatedBytes();
+    }
+
+    /** @return total CPU time in milliseconds for executing request */
+    public long getTotalCpuTime() {
+      return (threadMxBean.getCurrentThreadCpuTime() - startedTotalCpu) / 1_000_000;
+    }
+
+    /** @return CPU time in user mode in milliseconds for executing request */
+    public long getUserCpuTime() {
+      return (threadMxBean.getCurrentThreadUserTime() - startedUserCpu) / 1_000_000;
+    }
+
+    /** @return memory allocated in bytes for executing request */
+    public long getAllocatedMemory() {
+      return startedMemory == -1
+          ? -1
+          : threadMxBean.getCurrentThreadAllocatedBytes() - startedMemory;
+    }
+  }
+
   private final RequestMetrics metrics;
 
   @Inject
@@ -52,6 +86,7 @@
   @Override
   public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
       throws IOException, ServletException {
+    request.setAttribute(METRICS_CONTEXT, new Context());
     Response rsp = new Response((HttpServletResponse) response, metrics);
 
     chain.doFilter(request, rsp);
diff --git a/java/com/google/gerrit/metrics/proc/ProcMetricModule.java b/java/com/google/gerrit/metrics/proc/ProcMetricModule.java
index 20ac8fa..09e40c1 100644
--- a/java/com/google/gerrit/metrics/proc/ProcMetricModule.java
+++ b/java/com/google/gerrit/metrics/proc/ProcMetricModule.java
@@ -27,6 +27,7 @@
 import java.lang.management.GarbageCollectorMXBean;
 import java.lang.management.ManagementFactory;
 import java.lang.management.MemoryMXBean;
+import java.lang.management.MemoryPoolMXBean;
 import java.lang.management.MemoryUsage;
 import java.lang.management.OperatingSystemMXBean;
 import java.lang.management.ThreadMXBean;
@@ -41,6 +42,7 @@
     procCpuLoad(metrics);
     procJvmGc(metrics);
     procJvmMemory(metrics);
+    procJvmMemoryPool(metrics);
     procJvmThread(metrics);
   }
 
@@ -167,6 +169,50 @@
         });
   }
 
+  private void procJvmMemoryPool(MetricMaker metrics) {
+    Field<String> poolName =
+        Field.ofString("pool_name", Metadata.Builder::memoryPoolName)
+            .description("The name of the memory pool")
+            .build();
+
+    CallbackMetric1<String, Long> committed =
+        metrics.newCallbackMetric(
+            "proc/jvm/memory/pool/committed",
+            Long.class,
+            new Description("Committed pool size").setUnit(Units.BYTES),
+            poolName);
+
+    CallbackMetric1<String, Long> max =
+        metrics.newCallbackMetric(
+            "proc/jvm/memory/pool/max",
+            Long.class,
+            new Description("Max pool size").setUnit(Units.BYTES),
+            poolName);
+
+    CallbackMetric1<String, Long> used =
+        metrics.newCallbackMetric(
+            "proc/jvm/memory/pool/used",
+            Long.class,
+            new Description("Used pool size").setUnit(Units.BYTES),
+            poolName);
+
+    metrics.newTrigger(
+        committed,
+        max,
+        used,
+        () -> {
+          for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) {
+            if (!pool.isValid()) {
+              continue;
+            }
+            MemoryUsage u = pool.getUsage();
+            committed.set(pool.getName(), u.getCommitted());
+            max.set(pool.getName(), u.getMax());
+            used.set(pool.getName(), u.getUsed());
+          }
+        });
+  }
+
   private void procJvmGc(MetricMaker metrics) {
     Field<String> gcNameField =
         Field.ofString("gc_name", Metadata.Builder::garbageCollectorName)
diff --git a/java/com/google/gerrit/metrics/proc/ThreadMXBeanFactory.java b/java/com/google/gerrit/metrics/proc/ThreadMXBeanFactory.java
new file mode 100644
index 0000000..1e0c4f0
--- /dev/null
+++ b/java/com/google/gerrit/metrics/proc/ThreadMXBeanFactory.java
@@ -0,0 +1,31 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.metrics.proc;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadMXBean;
+
+public class ThreadMXBeanFactory {
+
+  private ThreadMXBeanFactory() {}
+
+  public static ThreadMXBeanInterface create() {
+    ThreadMXBean sys = ManagementFactory.getThreadMXBean();
+    if (sys instanceof com.sun.management.ThreadMXBean) {
+      return new ThreadMXBeanSun(sys);
+    }
+    return new ThreadMXBeanJava(sys);
+  }
+}
diff --git a/java/com/google/gerrit/metrics/proc/ThreadMXBeanInterface.java b/java/com/google/gerrit/metrics/proc/ThreadMXBeanInterface.java
new file mode 100644
index 0000000..546924f
--- /dev/null
+++ b/java/com/google/gerrit/metrics/proc/ThreadMXBeanInterface.java
@@ -0,0 +1,22 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.gerrit.metrics.proc;
+
+public interface ThreadMXBeanInterface {
+  long getCurrentThreadCpuTime();
+
+  long getCurrentThreadUserTime();
+
+  long getCurrentThreadAllocatedBytes();
+}
diff --git a/java/com/google/gerrit/metrics/proc/ThreadMXBeanJava.java b/java/com/google/gerrit/metrics/proc/ThreadMXBeanJava.java
new file mode 100644
index 0000000..29dd42a
--- /dev/null
+++ b/java/com/google/gerrit/metrics/proc/ThreadMXBeanJava.java
@@ -0,0 +1,40 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.metrics.proc;
+
+import java.lang.management.ThreadMXBean;
+
+class ThreadMXBeanJava implements ThreadMXBeanInterface {
+  private final ThreadMXBean sys;
+
+  ThreadMXBeanJava(ThreadMXBean sys) {
+    this.sys = sys;
+  }
+
+  @Override
+  public long getCurrentThreadCpuTime() {
+    return sys.getCurrentThreadCpuTime();
+  }
+
+  @Override
+  public long getCurrentThreadUserTime() {
+    return sys.getCurrentThreadUserTime();
+  }
+
+  @Override
+  public long getCurrentThreadAllocatedBytes() {
+    return -1;
+  }
+}
diff --git a/java/com/google/gerrit/metrics/proc/ThreadMXBeanSun.java b/java/com/google/gerrit/metrics/proc/ThreadMXBeanSun.java
new file mode 100644
index 0000000..9e43a05
--- /dev/null
+++ b/java/com/google/gerrit/metrics/proc/ThreadMXBeanSun.java
@@ -0,0 +1,42 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.metrics.proc;
+
+import com.sun.management.ThreadMXBean;
+
+class ThreadMXBeanSun implements ThreadMXBeanInterface {
+  private final ThreadMXBean sys;
+
+  ThreadMXBeanSun(java.lang.management.ThreadMXBean sys) {
+    this.sys = (ThreadMXBean) sys;
+  }
+
+  @Override
+  public long getCurrentThreadCpuTime() {
+    return sys.getCurrentThreadCpuTime();
+  }
+
+  @Override
+  public long getCurrentThreadUserTime() {
+    return sys.getCurrentThreadUserTime();
+  }
+
+  @Override
+  public long getCurrentThreadAllocatedBytes() {
+    // TODO(ms): call getCurrentThreadAllocatedBytes as soon as this is available in the patched
+    // Java version used by bazel
+    return sys.getThreadAllocatedBytes(Thread.currentThread().getId());
+  }
+}
diff --git a/java/com/google/gerrit/pgm/http/jetty/HttpLog.java b/java/com/google/gerrit/pgm/http/jetty/HttpLog.java
index 4e4c93b..2353116 100644
--- a/java/com/google/gerrit/pgm/http/jetty/HttpLog.java
+++ b/java/com/google/gerrit/pgm/http/jetty/HttpLog.java
@@ -16,6 +16,7 @@
 
 import com.google.common.base.Strings;
 import com.google.gerrit.httpd.GetUserFilter;
+import com.google.gerrit.httpd.RequestMetricsFilter;
 import com.google.gerrit.httpd.restapi.LogRedactUtil;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.util.SystemLog;
@@ -51,6 +52,9 @@
   protected static final String P_LATENCY = "Latency";
   protected static final String P_REFERER = "Referer";
   protected static final String P_USER_AGENT = "User-Agent";
+  protected static final String P_CPU_TOTAL = "Cpu-Total";
+  protected static final String P_CPU_USER = "Cpu-User";
+  protected static final String P_MEMORY = "Memory";
 
   private final AsyncAppender async;
 
@@ -114,6 +118,12 @@
     set(event, P_REFERER, req.getHeader("Referer"));
     set(event, P_USER_AGENT, req.getHeader("User-Agent"));
 
+    RequestMetricsFilter.Context ctx =
+        (RequestMetricsFilter.Context) req.getAttribute(RequestMetricsFilter.METRICS_CONTEXT);
+    set(event, P_CPU_TOTAL, ctx.getTotalCpuTime());
+    set(event, P_CPU_USER, ctx.getUserCpuTime());
+    set(event, P_MEMORY, ctx.getAllocatedMemory());
+
     async.append(event);
   }
 
diff --git a/java/com/google/gerrit/pgm/http/jetty/HttpLogJsonLayout.java b/java/com/google/gerrit/pgm/http/jetty/HttpLogJsonLayout.java
index 95a5b07..5f4ec43 100644
--- a/java/com/google/gerrit/pgm/http/jetty/HttpLogJsonLayout.java
+++ b/java/com/google/gerrit/pgm/http/jetty/HttpLogJsonLayout.java
@@ -15,8 +15,11 @@
 package com.google.gerrit.pgm.http.jetty;
 
 import static com.google.gerrit.pgm.http.jetty.HttpLog.P_CONTENT_LENGTH;
+import static com.google.gerrit.pgm.http.jetty.HttpLog.P_CPU_TOTAL;
+import static com.google.gerrit.pgm.http.jetty.HttpLog.P_CPU_USER;
 import static com.google.gerrit.pgm.http.jetty.HttpLog.P_HOST;
 import static com.google.gerrit.pgm.http.jetty.HttpLog.P_LATENCY;
+import static com.google.gerrit.pgm.http.jetty.HttpLog.P_MEMORY;
 import static com.google.gerrit.pgm.http.jetty.HttpLog.P_METHOD;
 import static com.google.gerrit.pgm.http.jetty.HttpLog.P_PROTOCOL;
 import static com.google.gerrit.pgm.http.jetty.HttpLog.P_REFERER;
@@ -48,6 +51,9 @@
     public String status;
     public String contentLength;
     public String latency;
+    public String cpuTotal;
+    public String cpuUser;
+    public String memory;
     public String referer;
     public String userAgent;
 
@@ -62,6 +68,9 @@
       this.status = getMdcString(event, P_STATUS);
       this.contentLength = getMdcString(event, P_CONTENT_LENGTH);
       this.latency = getMdcString(event, P_LATENCY);
+      this.cpuTotal = getMdcString(event, P_CPU_TOTAL);
+      this.cpuUser = getMdcString(event, P_CPU_USER);
+      this.memory = getMdcString(event, P_MEMORY);
       this.referer = getMdcString(event, P_REFERER);
       this.userAgent = getMdcString(event, P_USER_AGENT);
     }
diff --git a/java/com/google/gerrit/pgm/http/jetty/HttpLogLayout.java b/java/com/google/gerrit/pgm/http/jetty/HttpLogLayout.java
index 268f59f..e9e6866 100644
--- a/java/com/google/gerrit/pgm/http/jetty/HttpLogLayout.java
+++ b/java/com/google/gerrit/pgm/http/jetty/HttpLogLayout.java
@@ -71,6 +71,15 @@
     buf.append(' ');
     dq_opt(buf, event, HttpLog.P_USER_AGENT);
 
+    buf.append(' ');
+    opt(buf, event, HttpLog.P_CPU_TOTAL);
+
+    buf.append(' ');
+    opt(buf, event, HttpLog.P_CPU_USER);
+
+    buf.append(' ');
+    opt(buf, event, HttpLog.P_MEMORY);
+
     buf.append('\n');
     return buf.toString();
   }
diff --git a/java/com/google/gerrit/server/change/ActionJson.java b/java/com/google/gerrit/server/change/ActionJson.java
index 6f28dad..54ebf40 100644
--- a/java/com/google/gerrit/server/change/ActionJson.java
+++ b/java/com/google/gerrit/server/change/ActionJson.java
@@ -31,7 +31,7 @@
 import com.google.gerrit.extensions.webui.UiAction;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.extensions.webui.UiActions;
-import com.google.gerrit.server.notedb.ChangeNotes;
+import com.google.gerrit.server.query.change.ChangeData;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
@@ -89,9 +89,9 @@
     return Lists.newArrayList(visitorSet);
   }
 
-  void addChangeActions(ChangeInfo to, ChangeNotes notes) {
+  void addChangeActions(ChangeInfo to, ChangeData changeData) {
     List<ActionVisitor> visitors = visitors();
-    to.actions = toActionMap(notes, visitors, copy(visitors, to));
+    to.actions = toActionMap(changeData, visitors, copy(visitors, to));
   }
 
   void addRevisionActions(@Nullable ChangeInfo changeInfo, RevisionInfo to, RevisionResource rsrc) {
@@ -167,7 +167,7 @@
   }
 
   private Map<String, ActionInfo> toActionMap(
-      ChangeNotes notes, List<ActionVisitor> visitors, ChangeInfo changeInfo) {
+      ChangeData changeData, List<ActionVisitor> visitors, ChangeInfo changeInfo) {
     CurrentUser user = userProvider.get();
     Map<String, ActionInfo> out = new LinkedHashMap<>();
     if (!user.isIdentifiedUser()) {
@@ -175,12 +175,12 @@
     }
 
     Iterable<UiAction.Description> descs =
-        uiActions.from(changeViews, changeResourceFactory.create(notes, user));
+        uiActions.from(changeViews, changeResourceFactory.create(changeData, user));
 
     // The followup action is a client-side only operation that does not
     // have a server side handler. It must be manually registered into the
     // resulting action map.
-    if (!notes.getChange().isAbandoned()) {
+    if (!changeData.change().isAbandoned()) {
       UiAction.Description descr = new UiAction.Description();
       PrivateInternals_UiActionDescription.setId(descr, "followup");
       PrivateInternals_UiActionDescription.setMethod(descr, "POST");
diff --git a/java/com/google/gerrit/server/change/ChangeJson.java b/java/com/google/gerrit/server/change/ChangeJson.java
index 09db24d..0320fc4 100644
--- a/java/com/google/gerrit/server/change/ChangeJson.java
+++ b/java/com/google/gerrit/server/change/ChangeJson.java
@@ -677,7 +677,7 @@
     }
 
     if (has(CURRENT_ACTIONS) || has(CHANGE_ACTIONS)) {
-      actionJson.addChangeActions(out, cd.notes());
+      actionJson.addChangeActions(out, cd);
     }
 
     if (has(TRACKING_IDS)) {
diff --git a/java/com/google/gerrit/server/change/ChangeResource.java b/java/com/google/gerrit/server/change/ChangeResource.java
index 5a1798d..3729b59 100644
--- a/java/com/google/gerrit/server/change/ChangeResource.java
+++ b/java/com/google/gerrit/server/change/ChangeResource.java
@@ -44,9 +44,10 @@
 import com.google.gerrit.server.plugincontext.PluginSetContext;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.project.ProjectState;
-import com.google.inject.Inject;
+import com.google.gerrit.server.query.change.ChangeData;
 import com.google.inject.TypeLiteral;
 import com.google.inject.assistedinject.Assisted;
+import com.google.inject.assistedinject.AssistedInject;
 import java.util.HashSet;
 import java.util.Optional;
 import java.util.Set;
@@ -66,6 +67,8 @@
 
   public interface Factory {
     ChangeResource create(ChangeNotes notes, CurrentUser user);
+
+    ChangeResource create(ChangeData changeData, CurrentUser user);
   }
 
   private static final String ZERO_ID_STRING = ObjectId.zeroId().name();
@@ -77,10 +80,10 @@
   private final StarredChangesUtil starredChangesUtil;
   private final ProjectCache projectCache;
   private final PluginSetContext<ChangeETagComputation> changeETagComputation;
-  private final ChangeNotes notes;
+  private final ChangeData changeData;
   private final CurrentUser user;
 
-  @Inject
+  @AssistedInject
   ChangeResource(
       AccountCache accountCache,
       ApprovalsUtil approvalUtil,
@@ -89,6 +92,7 @@
       StarredChangesUtil starredChangesUtil,
       ProjectCache projectCache,
       PluginSetContext<ChangeETagComputation> changeETagComputation,
+      ChangeData.Factory changeDataFactory,
       @Assisted ChangeNotes notes,
       @Assisted CurrentUser user) {
     this.accountCache = accountCache;
@@ -98,12 +102,34 @@
     this.starredChangesUtil = starredChangesUtil;
     this.projectCache = projectCache;
     this.changeETagComputation = changeETagComputation;
-    this.notes = notes;
+    this.changeData = changeDataFactory.create(notes);
+    this.user = user;
+  }
+
+  @AssistedInject
+  ChangeResource(
+      AccountCache accountCache,
+      ApprovalsUtil approvalUtil,
+      PatchSetUtil patchSetUtil,
+      PermissionBackend permissionBackend,
+      StarredChangesUtil starredChangesUtil,
+      ProjectCache projectCache,
+      PluginSetContext<ChangeETagComputation> changeETagComputation,
+      @Assisted ChangeData changeData,
+      @Assisted CurrentUser user) {
+    this.accountCache = accountCache;
+    this.approvalUtil = approvalUtil;
+    this.patchSetUtil = patchSetUtil;
+    this.permissionBackend = permissionBackend;
+    this.starredChangesUtil = starredChangesUtil;
+    this.projectCache = projectCache;
+    this.changeETagComputation = changeETagComputation;
+    this.changeData = changeData;
     this.user = user;
   }
 
   public PermissionBackend.ForChange permissions() {
-    return permissionBackend.user(user).change(notes);
+    return permissionBackend.user(user).change(getNotes());
   }
 
   public CurrentUser getUser() {
@@ -111,7 +137,7 @@
   }
 
   public Change.Id getId() {
-    return notes.getChangeId();
+    return changeData.getId();
   }
 
   /** @return true if {@link #getUser()} is the change's owner. */
@@ -121,7 +147,7 @@
   }
 
   public Change getChange() {
-    return notes.getChange();
+    return changeData.change();
   }
 
   public Project.NameKey getProject() {
@@ -129,7 +155,11 @@
   }
 
   public ChangeNotes getNotes() {
-    return notes;
+    return changeData.notes();
+  }
+
+  public ChangeData getChangeData() {
+    return changeData;
   }
 
   // This includes all information relevant for ETag computation
@@ -153,7 +183,7 @@
       accounts.add(getChange().getAssignee());
     }
     try {
-      patchSetUtil.byChange(notes).stream().map(PatchSet::uploader).forEach(accounts::add);
+      patchSetUtil.byChange(getNotes()).stream().map(PatchSet::uploader).forEach(accounts::add);
 
       // It's intentional to include the states for *all* reviewers into the ETag computation.
       // We need the states of all current reviewers and CCs because they are part of ChangeInfo.
@@ -162,7 +192,7 @@
       // set of accounts that posted a message is too expensive. However everyone who posts a
       // message is automatically added as reviewer. Hence if we include removed reviewers we can
       // be sure that we have all accounts that posted messages on the change.
-      accounts.addAll(approvalUtil.getReviewers(notes).all());
+      accounts.addAll(approvalUtil.getReviewers(getNotes()).all());
     } catch (StorageException e) {
       // This ETag will be invalidated if it loads next time.
     }
@@ -178,7 +208,7 @@
 
     ObjectId noteId;
     try {
-      noteId = notes.loadRevision();
+      noteId = getNotes().loadRevision();
     } catch (StorageException e) {
       noteId = null; // This ETag will be invalidated if it loads next time.
     }
@@ -194,7 +224,7 @@
 
     changeETagComputation.runEach(
         c -> {
-          String pluginETag = c.getETag(notes.getProjectName(), notes.getChangeId());
+          String pluginETag = c.getETag(changeData.project(), changeData.getId());
           if (pluginETag != null) {
             h.putString(pluginETag, UTF_8);
           }
@@ -207,8 +237,8 @@
         TraceContext.newTimer(
             "Compute change ETag",
             Metadata.builder()
-                .changeId(notes.getChangeId().get())
-                .projectName(notes.getProjectName().get())
+                .changeId(changeData.getId().get())
+                .projectName(changeData.project().get())
                 .build())) {
       Hasher h = Hashing.murmur3_128().newHasher();
       if (user.isIdentifiedUser()) {
diff --git a/java/com/google/gerrit/server/change/RevisionJson.java b/java/com/google/gerrit/server/change/RevisionJson.java
index 558bdba..b702440 100644
--- a/java/com/google/gerrit/server/change/RevisionJson.java
+++ b/java/com/google/gerrit/server/change/RevisionJson.java
@@ -327,7 +327,7 @@
       actionJson.addRevisionActions(
           changeInfo,
           out,
-          new RevisionResource(changeResourceFactory.create(cd.notes(), userProvider.get()), in));
+          new RevisionResource(changeResourceFactory.create(cd, userProvider.get()), in));
     }
 
     if (gpgApi.isEnabled() && has(PUSH_CERTIFICATES)) {
diff --git a/java/com/google/gerrit/server/index/change/ChangeField.java b/java/com/google/gerrit/server/index/change/ChangeField.java
index c1b2dc7..9a0ae75 100644
--- a/java/com/google/gerrit/server/index/change/ChangeField.java
+++ b/java/com/google/gerrit/server/index/change/ChangeField.java
@@ -179,6 +179,11 @@
       exact(ChangeQueryBuilder.FIELD_HASHTAG)
           .buildRepeatable(cd -> cd.hashtags().stream().map(String::toLowerCase).collect(toSet()));
 
+  /** Hashtags as fulltext field for in-string search. */
+  public static final FieldDef<ChangeData, Iterable<String>> FUZZY_HASHTAG =
+      fullText("hashtag2")
+          .buildRepeatable(cd -> cd.hashtags().stream().map(String::toLowerCase).collect(toSet()));
+
   /** Hashtags with original case. */
   public static final FieldDef<ChangeData, Iterable<byte[]>> HASHTAG_CASE_AWARE =
       storedOnly("_hashtag")
diff --git a/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java b/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java
index 969b071..ffccb51 100644
--- a/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java
+++ b/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java
@@ -135,9 +135,14 @@
       new Schema.Builder<ChangeData>().add(V59).add(ChangeField.MERGE).build();
 
   /** Added new field {@link ChangeField#MERGED_ON} */
+  @Deprecated
   static final Schema<ChangeData> V61 =
       new Schema.Builder<ChangeData>().add(V60).add(ChangeField.MERGED_ON).build();
 
+  /** Added new field {@link ChangeField#FUZZY_HASHTAG} */
+  static final Schema<ChangeData> V62 =
+      new Schema.Builder<ChangeData>().add(V61).add(ChangeField.FUZZY_HASHTAG).build();
+
   /**
    * Name of the change index to be used when contacting index backends or loading configurations.
    */
diff --git a/java/com/google/gerrit/server/logging/Metadata.java b/java/com/google/gerrit/server/logging/Metadata.java
index 1a4a335..71ee01f 100644
--- a/java/com/google/gerrit/server/logging/Metadata.java
+++ b/java/com/google/gerrit/server/logging/Metadata.java
@@ -103,6 +103,9 @@
   public abstract Optional<Integer> indexVersion();
 
   /** The name of the implementation method. */
+  public abstract Optional<String> memoryPoolName();
+
+  /** The name of the implementation method. */
   public abstract Optional<String> methodName();
 
   /** One or more resources */
@@ -309,6 +312,8 @@
 
     public abstract Builder indexVersion(int indexVersion);
 
+    public abstract Builder memoryPoolName(@Nullable String memoryPoolName);
+
     public abstract Builder methodName(@Nullable String methodName);
 
     public abstract Builder multiple(boolean multiple);
diff --git a/java/com/google/gerrit/server/patch/AutoMerger.java b/java/com/google/gerrit/server/patch/AutoMerger.java
index 3f17a2e..b99e2d2 100644
--- a/java/com/google/gerrit/server/patch/AutoMerger.java
+++ b/java/com/google/gerrit/server/patch/AutoMerger.java
@@ -162,6 +162,11 @@
       return Optional.empty();
     }
 
+    if (repoView.getRef(RefNames.refsCacheAutomerge(maybeMergeCommit.name())).isPresent()) {
+      logger.atFine().log("AutoMerge alredy exists");
+      return Optional.empty();
+    }
+
     ObjectId autoMerge;
     try (Timer1.Context ignored = latency.start(OperationType.ON_DISK_WRITE)) {
       autoMerge =
diff --git a/java/com/google/gerrit/server/plugins/JsPlugin.java b/java/com/google/gerrit/server/plugins/JsPlugin.java
index 12028b60..c120cdd 100644
--- a/java/com/google/gerrit/server/plugins/JsPlugin.java
+++ b/java/com/google/gerrit/server/plugins/JsPlugin.java
@@ -40,8 +40,7 @@
     String fileName = getSrcFile().getFileName().toString();
     int firstDash = fileName.indexOf("-");
     if (firstDash > 0) {
-      int extension =
-          fileName.endsWith(".js") ? fileName.lastIndexOf(".js") : fileName.lastIndexOf(".html");
+      int extension = fileName.lastIndexOf(".js");
       if (extension > 0) {
         return fileName.substring(firstDash + 1, extension);
       }
diff --git a/java/com/google/gerrit/server/plugins/PluginLoader.java b/java/com/google/gerrit/server/plugins/PluginLoader.java
index c4f4a1f..0a06081 100644
--- a/java/com/google/gerrit/server/plugins/PluginLoader.java
+++ b/java/com/google/gerrit/server/plugins/PluginLoader.java
@@ -733,7 +733,7 @@
   }
 
   private boolean isUiPlugin(String name) {
-    return isPlugin(name, "js") || isPlugin(name, "html");
+    return isPlugin(name, "js");
   }
 
   private boolean isPlugin(String fileName, String ext) {
diff --git a/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java b/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
index c3bcd25..a7659d4 100644
--- a/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
+++ b/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
@@ -18,7 +18,6 @@
 import static com.google.gerrit.server.project.ProjectCache.noSuchProject;
 
 import com.google.common.collect.Streams;
-import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.entities.Change;
 import com.google.gerrit.entities.SubmitRecord;
 import com.google.gerrit.entities.SubmitTypeRecord;
@@ -34,7 +33,6 @@
 import com.google.gerrit.server.rules.SubmitRule;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
-import java.util.Collections;
 import java.util.List;
 import java.util.Optional;
 
@@ -43,10 +41,6 @@
  * the results through rules found in the parent projects, all the way up to All-Projects.
  */
 public class SubmitRuleEvaluator {
-  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
-
-  private static final String DEFAULT_MSG = "Error evaluating project rules, check server log";
-
   private final ProjectCache projectCache;
   private final PrologRule prologRule;
   private final PluginSetContext<SubmitRule> submitRules;
@@ -85,21 +79,6 @@
     this.opts = options;
   }
 
-  public static SubmitRecord defaultRuleError() {
-    return createRuleError(DEFAULT_MSG);
-  }
-
-  public static SubmitRecord createRuleError(String err) {
-    SubmitRecord rec = new SubmitRecord();
-    rec.status = SubmitRecord.Status.RULE_ERROR;
-    rec.errorMessage = err;
-    return rec;
-  }
-
-  public static SubmitTypeRecord defaultTypeError() {
-    return SubmitTypeRecord.error(DEFAULT_MSG);
-  }
-
   /**
    * Evaluate the submit rules.
    *
@@ -117,8 +96,8 @@
         }
 
         projectCache.get(cd.project()).orElseThrow(noSuchProject(cd.project()));
-      } catch (StorageException | NoSuchProjectException e) {
-        return Collections.singletonList(ruleError("Error looking up change " + cd.getId(), e));
+      } catch (NoSuchProjectException e) {
+        throw new IllegalStateException("Unable to find project while evaluating submit rule", e);
       }
 
       if (change.isClosed() && (!opts.recomputeOnClosedChanges() || OnlineReindexMode.isActive())) {
@@ -145,11 +124,6 @@
     }
   }
 
-  private SubmitRecord ruleError(String err, Exception e) {
-    logger.atSevere().withCause(e).log(err);
-    return defaultRuleError();
-  }
-
   /**
    * Evaluate the submit type rules to get the submit type.
    *
@@ -161,15 +135,10 @@
       try {
         projectCache.get(cd.project()).orElseThrow(noSuchProject(cd.project()));
       } catch (NoSuchProjectException e) {
-        return typeError("Error looking up change " + cd.getId(), e);
+        throw new IllegalStateException("Unable to find project while evaluating submit rule", e);
       }
 
       return prologRule.getSubmitType(cd);
     }
   }
-
-  private SubmitTypeRecord typeError(String err, Exception e) {
-    logger.atSevere().withCause(e).log(err);
-    return defaultTypeError();
-  }
 }
diff --git a/java/com/google/gerrit/server/query/change/ChangeData.java b/java/com/google/gerrit/server/query/change/ChangeData.java
index d7fc14b..793e4ec 100644
--- a/java/com/google/gerrit/server/query/change/ChangeData.java
+++ b/java/com/google/gerrit/server/query/change/ChangeData.java
@@ -318,7 +318,6 @@
   private Optional<ChangedLines> changedLines;
   private SubmitTypeRecord submitTypeRecord;
   private Boolean mergeable;
-  private Boolean merge;
   private Set<String> hashtags;
   private Map<Account.Id, Ref> editsByUser;
   private Set<Account.Id> reviewedBy;
@@ -334,7 +333,7 @@
   private PersonIdent author;
   private PersonIdent committer;
   private ImmutableSet<AttentionSetUpdate> attentionSet;
-  private int parentCount;
+  private Integer parentCount;
   private Integer unresolvedCommentCount;
   private Integer totalCommentCount;
   private LabelTypes labelTypes;
@@ -631,7 +630,6 @@
       author = c.getAuthorIdent();
       committer = c.getCommitterIdent();
       parentCount = c.getParentCount();
-      merge = parentCount > 1;
     } catch (IOException e) {
       throw new StorageException(
           String.format(
@@ -987,12 +985,12 @@
 
   @Nullable
   public Boolean isMerge() {
-    if (merge == null) {
+    if (parentCount == null) {
       if (!loadCommitData()) {
         return null;
       }
     }
-    return merge;
+    return parentCount > 1;
   }
 
   public Set<Account.Id> editsByUser() {
diff --git a/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java b/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
index 4e3edcd..6e2f49c 100644
--- a/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
+++ b/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
@@ -790,7 +790,23 @@
 
   @Operator
   public Predicate<ChangeData> hashtag(String hashtag) {
-    return new HashtagPredicate(hashtag);
+    return new ExactHashtagPredicate(hashtag);
+  }
+
+  @Operator
+  public Predicate<ChangeData> inhashtag(String hashtag) throws QueryParseException {
+    if (hashtag.startsWith("^")) {
+      return new RegexHashtagPredicate(hashtag);
+    }
+    if (hashtag.isEmpty()) {
+      return new ExactHashtagPredicate(hashtag);
+    }
+
+    if (!args.index.getSchema().hasField(ChangeField.FUZZY_HASHTAG)) {
+      throw new QueryParseException(
+          "'inhashtag' operator is not supported by change index version");
+    }
+    return new FuzzyHashtagPredicate(hashtag, args.index);
   }
 
   @Operator
diff --git a/java/com/google/gerrit/server/query/change/HashtagPredicate.java b/java/com/google/gerrit/server/query/change/ExactHashtagPredicate.java
similarity index 77%
rename from java/com/google/gerrit/server/query/change/HashtagPredicate.java
rename to java/com/google/gerrit/server/query/change/ExactHashtagPredicate.java
index 1fe4af4..a6526f7 100644
--- a/java/com/google/gerrit/server/query/change/HashtagPredicate.java
+++ b/java/com/google/gerrit/server/query/change/ExactHashtagPredicate.java
@@ -14,19 +14,23 @@
 
 package com.google.gerrit.server.query.change;
 
+import com.google.common.base.Strings;
 import com.google.gerrit.server.change.HashtagsUtil;
 import com.google.gerrit.server.index.change.ChangeField;
 
-public class HashtagPredicate extends ChangeIndexPredicate {
-  public HashtagPredicate(String hashtag) {
+public class ExactHashtagPredicate extends ChangeIndexPredicate {
+  public ExactHashtagPredicate(String hashtag) {
     // Use toLowerCase without locale to match behavior in ChangeField.
     // TODO(dborowitz): Change both.
     super(ChangeField.HASHTAG, HashtagsUtil.cleanupHashtag(hashtag).toLowerCase());
   }
 
   @Override
-  public boolean match(ChangeData object) {
-    for (String hashtag : object.notes().load().getHashtags()) {
+  public boolean match(ChangeData cd) {
+    if (Strings.isNullOrEmpty(getValue())) {
+      return cd.hashtags().isEmpty();
+    }
+    for (String hashtag : cd.hashtags()) {
       if (hashtag.equalsIgnoreCase(getValue())) {
         return true;
       }
diff --git a/java/com/google/gerrit/server/query/change/FuzzyHashtagPredicate.java b/java/com/google/gerrit/server/query/change/FuzzyHashtagPredicate.java
new file mode 100644
index 0000000..35c96ef
--- /dev/null
+++ b/java/com/google/gerrit/server/query/change/FuzzyHashtagPredicate.java
@@ -0,0 +1,38 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.query.change;
+
+import static com.google.gerrit.server.index.change.ChangeField.FUZZY_HASHTAG;
+
+import com.google.gerrit.server.index.change.ChangeIndex;
+
+public class FuzzyHashtagPredicate extends ChangeIndexPredicate {
+  protected final ChangeIndex index;
+
+  public FuzzyHashtagPredicate(String hashtag, ChangeIndex index) {
+    super(FUZZY_HASHTAG, hashtag.toLowerCase());
+    this.index = index;
+  }
+
+  @Override
+  public boolean match(ChangeData cd) {
+    return cd.hashtags().stream().anyMatch(ht -> ht.toLowerCase().contains(getValue()));
+  }
+
+  @Override
+  public int getCost() {
+    return 1;
+  }
+}
diff --git a/java/com/google/gerrit/server/query/change/RegexHashtagPredicate.java b/java/com/google/gerrit/server/query/change/RegexHashtagPredicate.java
new file mode 100644
index 0000000..24efa6a
--- /dev/null
+++ b/java/com/google/gerrit/server/query/change/RegexHashtagPredicate.java
@@ -0,0 +1,51 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.query.change;
+
+import static com.google.gerrit.server.index.change.ChangeField.HASHTAG;
+
+import dk.brics.automaton.RegExp;
+import dk.brics.automaton.RunAutomaton;
+
+public class RegexHashtagPredicate extends ChangeRegexPredicate {
+  protected final RunAutomaton pattern;
+
+  public RegexHashtagPredicate(String re) {
+    super(HASHTAG, re);
+
+    if (re.startsWith("^")) {
+      re = re.substring(1);
+    }
+
+    if (re.endsWith("$") && !re.endsWith("\\$")) {
+      re = re.substring(0, re.length() - 1);
+    }
+
+    this.pattern = new RunAutomaton(new RegExp(re).toAutomaton());
+  }
+
+  @Override
+  public boolean match(ChangeData cd) {
+    if (cd.hashtags().isEmpty()) {
+      return false;
+    }
+    return cd.hashtags().stream().anyMatch(ht -> pattern.run(ht));
+  }
+
+  @Override
+  public int getCost() {
+    return 1;
+  }
+}
diff --git a/java/com/google/gerrit/server/restapi/change/Submit.java b/java/com/google/gerrit/server/restapi/change/Submit.java
index 790b2db..801340b 100644
--- a/java/com/google/gerrit/server/restapi/change/Submit.java
+++ b/java/com/google/gerrit/server/restapi/change/Submit.java
@@ -311,7 +311,7 @@
       throw new StorageException("Could not determine problems for the change", e);
     }
 
-    ChangeData cd = changeDataFactory.create(resource.getNotes());
+    ChangeData cd = resource.getChangeResource().getChangeData();
     try {
       MergeOp.checkSubmitRule(cd, false);
     } catch (ResourceConflictException e) {
diff --git a/java/com/google/gerrit/server/restapi/config/GetServerInfo.java b/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
index 0a5692e..c3dd1b5 100644
--- a/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
+++ b/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
@@ -320,17 +320,12 @@
     PluginConfigInfo info = new PluginConfigInfo();
     info.hasAvatars = toBoolean(avatar.hasImplementation());
     info.jsResourcePaths = new ArrayList<>();
-    info.htmlResourcePaths = new ArrayList<>();
     plugins.runEach(
         plugin -> {
           String path =
               String.format(
                   "plugins/%s/%s", plugin.getPluginName(), plugin.getJavaScriptResourcePath());
-          if (path.endsWith(".html")) {
-            info.htmlResourcePaths.add(path);
-          } else {
-            info.jsResourcePaths.add(path);
-          }
+          info.jsResourcePaths.add(path);
         });
     return info;
   }
diff --git a/java/com/google/gerrit/server/rules/DefaultSubmitRule.java b/java/com/google/gerrit/server/rules/DefaultSubmitRule.java
index 4592100..e670dc2 100644
--- a/java/com/google/gerrit/server/rules/DefaultSubmitRule.java
+++ b/java/com/google/gerrit/server/rules/DefaultSubmitRule.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.server.rules;
 
+import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.collect.ImmutableList.toImmutableList;
 import static com.google.gerrit.server.project.ProjectCache.illegalState;
 
@@ -22,7 +23,6 @@
 import com.google.gerrit.entities.LabelType;
 import com.google.gerrit.entities.PatchSetApproval;
 import com.google.gerrit.entities.SubmitRecord;
-import com.google.gerrit.exceptions.StorageException;
 import com.google.gerrit.extensions.annotations.Exports;
 import com.google.gerrit.extensions.config.FactoryModule;
 import com.google.gerrit.server.project.ProjectCache;
@@ -76,32 +76,17 @@
     SubmitRecord submitRecord = new SubmitRecord();
     submitRecord.status = SubmitRecord.Status.OK;
 
-    List<LabelType> labelTypes;
-    List<PatchSetApproval> approvals;
-    try {
-      labelTypes = cd.getLabelTypes().getLabelTypes();
-      approvals = cd.currentApprovals();
-    } catch (StorageException e) {
-      logger.atSevere().withCause(e).log(
-          "Unable to fetch labels and approvals for change %s", cd.getId());
-
-      submitRecord.errorMessage = "Unable to fetch labels and approvals for the change";
-      submitRecord.status = SubmitRecord.Status.RULE_ERROR;
-      return Optional.of(submitRecord);
-    }
-
+    List<LabelType> labelTypes = cd.getLabelTypes().getLabelTypes();
+    List<PatchSetApproval> approvals = cd.currentApprovals();
     submitRecord.labels = new ArrayList<>(labelTypes.size());
 
     for (LabelType t : labelTypes) {
       LabelFunction labelFunction = t.getFunction();
-      if (labelFunction == null) {
-        logger.atSevere().log(
-            "Unable to find the LabelFunction for label %s, change %s", t.getName(), cd.getId());
-
-        submitRecord.errorMessage = "Unable to find the LabelFunction for label " + t.getName();
-        submitRecord.status = SubmitRecord.Status.RULE_ERROR;
-        return Optional.of(submitRecord);
-      }
+      checkState(
+          labelFunction != null,
+          "Unable to find the LabelFunction for label %s, change %s",
+          t.getName(),
+          cd.getId());
 
       Collection<PatchSetApproval> approvalsForLabel = getApprovalsForLabel(approvals, t);
       SubmitRecord.Label label = labelFunction.check(t, approvalsForLabel);
diff --git a/java/com/google/gerrit/server/rules/IgnoreSelfApprovalRule.java b/java/com/google/gerrit/server/rules/IgnoreSelfApprovalRule.java
index b2bfbd5..4541330 100644
--- a/java/com/google/gerrit/server/rules/IgnoreSelfApprovalRule.java
+++ b/java/com/google/gerrit/server/rules/IgnoreSelfApprovalRule.java
@@ -17,14 +17,12 @@
 import static com.google.common.collect.ImmutableList.toImmutableList;
 
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.entities.Account;
 import com.google.gerrit.entities.LabelFunction;
 import com.google.gerrit.entities.LabelType;
 import com.google.gerrit.entities.PatchSetApproval;
 import com.google.gerrit.entities.SubmitRecord;
 import com.google.gerrit.entities.SubmitRequirement;
-import com.google.gerrit.exceptions.StorageException;
 import com.google.gerrit.extensions.annotations.Exports;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.inject.AbstractModule;
@@ -40,11 +38,6 @@
  */
 @Singleton
 public class IgnoreSelfApprovalRule implements SubmitRule {
-  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
-  private static final String E_UNABLE_TO_FETCH_UPLOADER = "Unable to fetch uploader";
-  private static final String E_UNABLE_TO_FETCH_LABELS =
-      "Unable to fetch labels and approvals for the change";
-
   public static class Module extends AbstractModule {
     @Override
     public void configure() {
@@ -56,16 +49,8 @@
 
   @Override
   public Optional<SubmitRecord> evaluate(ChangeData cd) {
-    List<LabelType> labelTypes;
-    List<PatchSetApproval> approvals;
-    try {
-      labelTypes = cd.getLabelTypes().getLabelTypes();
-      approvals = cd.currentApprovals();
-    } catch (StorageException e) {
-      logger.atWarning().withCause(e).log(E_UNABLE_TO_FETCH_LABELS);
-      return ruleError(E_UNABLE_TO_FETCH_LABELS);
-    }
-
+    List<LabelType> labelTypes = cd.getLabelTypes().getLabelTypes();
+    List<PatchSetApproval> approvals = cd.currentApprovals();
     boolean shouldIgnoreSelfApproval =
         labelTypes.stream().anyMatch(LabelType::isIgnoreSelfApproval);
     if (!shouldIgnoreSelfApproval) {
@@ -73,14 +58,7 @@
       return Optional.empty();
     }
 
-    Account.Id uploader;
-    try {
-      uploader = cd.currentPatchSet().uploader();
-    } catch (StorageException e) {
-      logger.atWarning().withCause(e).log(E_UNABLE_TO_FETCH_UPLOADER);
-      return ruleError(E_UNABLE_TO_FETCH_UPLOADER);
-    }
-
+    Account.Id uploader = cd.currentPatchSet().uploader();
     SubmitRecord submitRecord = new SubmitRecord();
     submitRecord.status = SubmitRecord.Status.OK;
     submitRecord.labels = new ArrayList<>(labelTypes.size());
@@ -140,13 +118,6 @@
     return false;
   }
 
-  private static Optional<SubmitRecord> ruleError(String reason) {
-    SubmitRecord submitRecord = new SubmitRecord();
-    submitRecord.errorMessage = reason;
-    submitRecord.status = SubmitRecord.Status.RULE_ERROR;
-    return Optional.of(submitRecord);
-  }
-
   @VisibleForTesting
   static Collection<PatchSetApproval> filterOutPositiveApprovalsOfUser(
       Collection<PatchSetApproval> approvals, Account.Id user) {
diff --git a/java/com/google/gerrit/server/rules/PrologRuleEvaluator.java b/java/com/google/gerrit/server/rules/PrologRuleEvaluator.java
index 57c4832..3dc5be0 100644
--- a/java/com/google/gerrit/server/rules/PrologRuleEvaluator.java
+++ b/java/com/google/gerrit/server/rules/PrologRuleEvaluator.java
@@ -16,9 +16,6 @@
 
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.gerrit.server.project.ProjectCache.illegalState;
-import static com.google.gerrit.server.project.SubmitRuleEvaluator.createRuleError;
-import static com.google.gerrit.server.project.SubmitRuleEvaluator.defaultRuleError;
-import static com.google.gerrit.server.project.SubmitRuleEvaluator.defaultTypeError;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.CharMatcher;
@@ -61,6 +58,9 @@
  */
 public class PrologRuleEvaluator {
   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+  private static final String DEFAULT_MSG = "Error evaluating project rules, check server log";
+
   /**
    * List of characters to allow in the label name, when an invalid name is used. Dash is allowed as
    * it can't be the first character: we use a prefix.
@@ -289,6 +289,13 @@
     return VALID_LABEL_MATCHER.retainFrom(name);
   }
 
+  private static SubmitRecord createRuleError(String err) {
+    SubmitRecord rec = new SubmitRecord();
+    rec.status = SubmitRecord.Status.RULE_ERROR;
+    rec.errorMessage = err;
+    return rec;
+  }
+
   private SubmitRecord invalidResult(Term rule, Term record, String reason) {
     return ruleError(
         String.format(
@@ -311,7 +318,7 @@
   private SubmitRecord ruleError(String err, Exception e) {
     if (opts.logErrors()) {
       logger.atSevere().withCause(e).log(err);
-      return defaultRuleError();
+      return createRuleError(DEFAULT_MSG);
     }
     return createRuleError(err);
   }
@@ -389,7 +396,7 @@
   private SubmitTypeRecord typeError(String err, Exception e) {
     if (opts.logErrors()) {
       logger.atSevere().withCause(e).log(err);
-      return defaultTypeError();
+      return typeError(DEFAULT_MSG);
     }
     return SubmitTypeRecord.error(err);
   }
diff --git a/java/com/google/gerrit/sshd/BaseCommand.java b/java/com/google/gerrit/sshd/BaseCommand.java
index 0ce6766..48a5512 100644
--- a/java/com/google/gerrit/sshd/BaseCommand.java
+++ b/java/com/google/gerrit/sshd/BaseCommand.java
@@ -36,7 +36,6 @@
 import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.project.NoSuchProjectException;
-import com.google.gerrit.server.util.time.TimeUtil;
 import com.google.gerrit.sshd.SshScope.Context;
 import com.google.gerrit.util.cli.CmdLineParser;
 import com.google.gerrit.util.cli.EndOfOptionsHandler;
@@ -480,7 +479,7 @@
         context.getSession().setAccessPath(accessPath);
         final Context old = sshScope.set(context);
         try {
-          context.started = TimeUtil.nowMs();
+          context.start();
           thisThread.setName("SSH " + taskName);
 
           try {
diff --git a/java/com/google/gerrit/sshd/SshLog.java b/java/com/google/gerrit/sshd/SshLog.java
index 2b3052c..616f7d1 100644
--- a/java/com/google/gerrit/sshd/SshLog.java
+++ b/java/com/google/gerrit/sshd/SshLog.java
@@ -57,6 +57,9 @@
   protected static final String P_STATUS = "status";
   protected static final String P_AGENT = "agent";
   protected static final String P_MESSAGE = "message";
+  protected static final String P_TOTAL_CPU = "totalCpu";
+  protected static final String P_USER_CPU = "userCpu";
+  protected static final String P_MEMORY = "memory";
 
   private final Provider<SshSession> session;
   private final Provider<Context> context;
@@ -171,13 +174,16 @@
 
   void onExecute(DispatchCommand dcmd, int exitValue, SshSession sshSession, String message) {
     final Context ctx = context.get();
-    ctx.finished = TimeUtil.nowMs();
+    ctx.finish();
 
     String cmd = extractWhat(dcmd);
 
     final LoggingEvent event = log(cmd);
-    event.setProperty(P_WAIT, (ctx.started - ctx.created) + "ms");
-    event.setProperty(P_EXEC, (ctx.finished - ctx.started) + "ms");
+    event.setProperty(P_WAIT, ctx.getWait() + "ms");
+    event.setProperty(P_EXEC, ctx.getExec() + "ms");
+    event.setProperty(P_TOTAL_CPU, ctx.getTotalCpu() + "ms");
+    event.setProperty(P_USER_CPU, ctx.getUserCpu() + "ms");
+    event.setProperty(P_MEMORY, String.valueOf(ctx.getAllocatedMemory()));
 
     final String status;
     switch (exitValue) {
@@ -328,7 +334,7 @@
       SshSession session = ctx.getSession();
       sessionId = HexFormat.fromInt(session.getSessionId());
       currentUser = session.getUser();
-      created = ctx.created;
+      created = ctx.getCreated();
     }
     auditService.dispatch(new SshAuditEvent(sessionId, currentUser, cmd, created, params, result));
   }
diff --git a/java/com/google/gerrit/sshd/SshLogJsonLayout.java b/java/com/google/gerrit/sshd/SshLogJsonLayout.java
index 488a4c5..fca0a5a 100644
--- a/java/com/google/gerrit/sshd/SshLogJsonLayout.java
+++ b/java/com/google/gerrit/sshd/SshLogJsonLayout.java
@@ -17,9 +17,12 @@
 import static com.google.gerrit.sshd.SshLog.P_ACCOUNT_ID;
 import static com.google.gerrit.sshd.SshLog.P_AGENT;
 import static com.google.gerrit.sshd.SshLog.P_EXEC;
+import static com.google.gerrit.sshd.SshLog.P_MEMORY;
 import static com.google.gerrit.sshd.SshLog.P_MESSAGE;
 import static com.google.gerrit.sshd.SshLog.P_SESSION;
 import static com.google.gerrit.sshd.SshLog.P_STATUS;
+import static com.google.gerrit.sshd.SshLog.P_TOTAL_CPU;
+import static com.google.gerrit.sshd.SshLog.P_USER_CPU;
 import static com.google.gerrit.sshd.SshLog.P_USER_NAME;
 import static com.google.gerrit.sshd.SshLog.P_WAIT;
 
@@ -44,6 +47,9 @@
     public String message;
     public String waitTime;
     public String execTime;
+    public String totalCpu;
+    public String userCpu;
+    public String memory;
     public String status;
     public String agent;
     public String timeNegotiating;
@@ -67,6 +73,9 @@
       this.message = (String) event.getMessage();
       this.waitTime = getMdcString(event, P_WAIT);
       this.execTime = getMdcString(event, P_EXEC);
+      this.totalCpu = getMdcString(event, P_TOTAL_CPU);
+      this.userCpu = getMdcString(event, P_USER_CPU);
+      this.memory = getMdcString(event, P_MEMORY);
       this.status = getMdcString(event, P_STATUS);
       this.agent = getMdcString(event, P_AGENT);
 
diff --git a/java/com/google/gerrit/sshd/SshLogLayout.java b/java/com/google/gerrit/sshd/SshLogLayout.java
index 1dda068..a1f2c40 100644
--- a/java/com/google/gerrit/sshd/SshLogLayout.java
+++ b/java/com/google/gerrit/sshd/SshLogLayout.java
@@ -17,9 +17,12 @@
 import static com.google.gerrit.sshd.SshLog.P_ACCOUNT_ID;
 import static com.google.gerrit.sshd.SshLog.P_AGENT;
 import static com.google.gerrit.sshd.SshLog.P_EXEC;
+import static com.google.gerrit.sshd.SshLog.P_MEMORY;
 import static com.google.gerrit.sshd.SshLog.P_MESSAGE;
 import static com.google.gerrit.sshd.SshLog.P_SESSION;
 import static com.google.gerrit.sshd.SshLog.P_STATUS;
+import static com.google.gerrit.sshd.SshLog.P_TOTAL_CPU;
+import static com.google.gerrit.sshd.SshLog.P_USER_CPU;
 import static com.google.gerrit.sshd.SshLog.P_USER_NAME;
 import static com.google.gerrit.sshd.SshLog.P_WAIT;
 
@@ -56,11 +59,17 @@
     buf.append(' ');
     buf.append(event.getMessage());
 
-    opt(P_WAIT, buf, event);
-    opt(P_EXEC, buf, event);
-    opt(P_MESSAGE, buf, event);
-    opt(P_STATUS, buf, event);
-    opt(P_AGENT, buf, event);
+    String msg = (String) event.getMessage();
+    if (!(msg.startsWith("LOGIN") || msg.equals("LOGOUT"))) {
+      req(P_WAIT, buf, event);
+      req(P_EXEC, buf, event);
+      req(P_MESSAGE, buf, event);
+      req(P_STATUS, buf, event);
+      req(P_AGENT, buf, event);
+      req(P_TOTAL_CPU, buf, event);
+      req(P_USER_CPU, buf, event);
+      req(P_MEMORY, buf, event);
+    }
 
     buf.append('\n');
     return buf.toString();
@@ -81,14 +90,6 @@
     }
   }
 
-  private void opt(String key, StringBuffer buf, LoggingEvent event) {
-    Object val = event.getMDC(key);
-    if (val != null) {
-      buf.append(' ');
-      buf.append(val);
-    }
-  }
-
   @Override
   public boolean ignoresThrowable() {
     return true;
diff --git a/java/com/google/gerrit/sshd/SshScope.java b/java/com/google/gerrit/sshd/SshScope.java
index 340b910..e9ed750 100644
--- a/java/com/google/gerrit/sshd/SshScope.java
+++ b/java/com/google/gerrit/sshd/SshScope.java
@@ -14,6 +14,8 @@
 
 package com.google.gerrit.sshd;
 
+import com.google.gerrit.metrics.proc.ThreadMXBeanFactory;
+import com.google.gerrit.metrics.proc.ThreadMXBeanInterface;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.RequestCleanup;
@@ -32,21 +34,32 @@
 /** Guice scopes for state during an SSH connection. */
 public class SshScope {
   private static final Key<RequestCleanup> RC_KEY = Key.get(RequestCleanup.class);
+  private static final ThreadMXBeanInterface threadMxBean = ThreadMXBeanFactory.create();
 
   class Context implements RequestContext {
+
     private final RequestCleanup cleanup = new RequestCleanup();
     private final Map<Key<?>, Object> map = new HashMap<>();
     private final SshSession session;
     private final String commandLine;
 
-    final long created;
-    volatile long started;
-    volatile long finished;
+    private final long created;
+    private volatile long started;
+    private volatile long finished;
+    private volatile long startedTotalCpu;
+    private volatile long finishedTotalCpu;
+    private volatile long startedUserCpu;
+    private volatile long finishedUserCpu;
+    private volatile long startedMemory;
+    private volatile long finishedMemory;
 
     private Context(SshSession s, String c, long at) {
       session = s;
       commandLine = c;
       created = started = finished = at;
+      startedTotalCpu = threadMxBean.getCurrentThreadCpuTime();
+      startedUserCpu = threadMxBean.getCurrentThreadUserTime();
+      startedMemory = threadMxBean.getCurrentThreadAllocatedBytes();
       map.put(RC_KEY, cleanup);
     }
 
@@ -54,6 +67,50 @@
       this(s, c, p.created);
       started = p.started;
       finished = p.finished;
+      startedTotalCpu = p.startedTotalCpu;
+      finishedTotalCpu = p.finishedTotalCpu;
+      startedUserCpu = p.startedUserCpu;
+      finishedUserCpu = p.finishedUserCpu;
+      startedMemory = p.startedMemory;
+      finishedMemory = p.finishedMemory;
+    }
+
+    void start() {
+      started = TimeUtil.nowMs();
+      startedTotalCpu = threadMxBean.getCurrentThreadCpuTime();
+      startedUserCpu = threadMxBean.getCurrentThreadUserTime();
+      startedMemory = threadMxBean.getCurrentThreadAllocatedBytes();
+    }
+
+    void finish() {
+      finished = TimeUtil.nowMs();
+      finishedTotalCpu = threadMxBean.getCurrentThreadCpuTime();
+      finishedUserCpu = threadMxBean.getCurrentThreadUserTime();
+      finishedMemory = threadMxBean.getCurrentThreadAllocatedBytes();
+    }
+
+    public long getCreated() {
+      return created;
+    }
+
+    public long getWait() {
+      return started - created;
+    }
+
+    public long getExec() {
+      return finished - started;
+    }
+
+    public long getTotalCpu() {
+      return (finishedTotalCpu - startedTotalCpu) / 1_000_000;
+    }
+
+    public long getUserCpu() {
+      return (finishedUserCpu - startedUserCpu) / 1_000_000;
+    }
+
+    public long getAllocatedMemory() {
+      return finishedMemory - startedMemory;
     }
 
     String getCommandLine() {
diff --git a/javatests/com/google/gerrit/acceptance/api/change/ChangeSubmitRequirementIT.java b/javatests/com/google/gerrit/acceptance/api/change/ChangeSubmitRequirementIT.java
index f55b24c..4448e87 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/ChangeSubmitRequirementIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/ChangeSubmitRequirementIT.java
@@ -179,10 +179,8 @@
         .id(changeId)
         .get(ListChangesOption.ALL_REVISIONS, ListChangesOption.CURRENT_ACTIONS);
 
-    // Submit rules are invoked twice, once for populating submit requirements in the change JSON
-    // and once for checking if the submit button should be visible.
-    // TODO(hiesel): Try to avoid calling submit rules twice.
-    assertThat(rule.numberOfEvaluations.get()).isEqualTo(2);
+    // Submit rules are computed freshly, but only once.
+    assertThat(rule.numberOfEvaluations.get()).isEqualTo(1);
   }
 
   @Test
@@ -196,9 +194,8 @@
         .withOptions(ListChangesOption.ALL_REVISIONS, ListChangesOption.CURRENT_ACTIONS)
         .get();
 
-    // Submit rules are invoked to check if the submit button should be visible.
-    // TODO(hiesel): Change queries must not trigger submit rules.
-    assertThat(rule.numberOfEvaluations.get()).isEqualTo(1);
+    // Submit rule evaluation results from the change index are reused
+    assertThat(rule.numberOfEvaluations.get()).isEqualTo(0);
   }
 
   private List<ChangeInfo> queryIsSubmittable() throws Exception {
diff --git a/javatests/com/google/gerrit/acceptance/api/plugin/PluginIT.java b/javatests/com/google/gerrit/acceptance/api/plugin/PluginIT.java
index 6838f8d..18eca27 100644
--- a/javatests/com/google/gerrit/acceptance/api/plugin/PluginIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/plugin/PluginIT.java
@@ -48,18 +48,14 @@
 @NoHttpd
 public class PluginIT extends AbstractDaemonTest {
   private static final String JS_PLUGIN = "Gerrit.install(function(self){});\n";
-  private static final String HTML_PLUGIN =
-      String.format("<dom-module id=\"test\"><script>%s</script></dom-module>", JS_PLUGIN);
   private static final RawInput JS_PLUGIN_CONTENT = RawInputUtil.create(JS_PLUGIN.getBytes(UTF_8));
-  private static final RawInput HTML_PLUGIN_CONTENT =
-      RawInputUtil.create(HTML_PLUGIN.getBytes(UTF_8));
 
   private static final ImmutableList<String> PLUGINS =
       ImmutableList.of(
           "plugin-a.js",
-          "plugin-b.html",
+          "plugin-b.js",
           "plugin-c.js",
-          "plugin-d.html",
+          "plugin-d.js",
           "plugin-normal.jar",
           "plugin-empty.jar",
           "plugin-unset.jar",
@@ -97,7 +93,7 @@
     assertPlugins(list().start(1).limit(2).get(), PLUGINS.subList(1, 3));
 
     // With prefix
-    assertPlugins(list().prefix("plugin-b").get(), ImmutableList.of("plugin-b.html"));
+    assertPlugins(list().prefix("plugin-b").get(), ImmutableList.of("plugin-b.js"));
     assertPlugins(list().prefix("PLUGIN-").get(), ImmutableList.of());
 
     // With substring
@@ -105,7 +101,7 @@
     assertPlugins(list().substring("lugin-").start(1).limit(2).get(), PLUGINS.subList(1, 3));
 
     // With regex
-    assertPlugins(list().regex(".*in-b").get(), ImmutableList.of("plugin-b.html"));
+    assertPlugins(list().regex(".*in-b").get(), ImmutableList.of("plugin-b.js"));
     assertPlugins(list().regex("plugin-.*").get(), PLUGINS.subList(0, PLUGINS.size() - 1));
     assertPlugins(list().regex("plugin-.*").start(1).limit(2).get(), PLUGINS.subList(1, 3));
 
@@ -147,7 +143,7 @@
     com.google.gerrit.extensions.common.InstallPluginInput input =
         new com.google.gerrit.extensions.common.InstallPluginInput();
     input.raw = JS_PLUGIN_CONTENT;
-    gApi.plugins().install("legacy.html", input);
+    gApi.plugins().install("legacy.js", input);
     gApi.plugins().name("legacy").get();
   }
 
@@ -198,9 +194,6 @@
     if (plugin.endsWith(".js")) {
       return JS_PLUGIN_CONTENT;
     }
-    if (plugin.endsWith(".html")) {
-      return HTML_PLUGIN_CONTENT;
-    }
     assertThat(plugin).endsWith(".jar");
     return pluginJarContent(plugin);
   }
diff --git a/javatests/com/google/gerrit/acceptance/git/AutoMergeIT.java b/javatests/com/google/gerrit/acceptance/git/AutoMergeIT.java
index 46688dd..b16394d 100644
--- a/javatests/com/google/gerrit/acceptance/git/AutoMergeIT.java
+++ b/javatests/com/google/gerrit/acceptance/git/AutoMergeIT.java
@@ -166,6 +166,25 @@
     assertNoAutoMergeCreated(result.getCommit());
   }
 
+  @Test
+  public void pushWorksIfAutoMergeExists() throws Exception {
+    PushOneCommit m =
+        pushFactory.create(
+            admin.newIdent(), testRepo, "merge", ImmutableMap.of("foo", "foo-1", "bar", "bar-2"));
+    m.setParents(ImmutableList.of(parent1, parent2));
+    PushOneCommit.Result result = m.to("refs/for/master");
+    result.assertOkStatus();
+    assertAutoMergeCreated(result.getCommit());
+
+    // Delete change and push commit again.
+    gApi.changes().id(result.getChangeId()).delete();
+
+    // Push again successfully and check that AutoMerge commit is still there
+    result = m.to("refs/for/master");
+    result.assertOkStatus();
+    assertAutoMergeCreated(result.getCommit());
+  }
+
   private void assertAutoMergeCreated(ObjectId mergeCommit) throws Exception {
     try (Repository repo = repoManager.openRepository(project)) {
       assertThat(repo.exactRef(RefNames.refsCacheAutomerge(mergeCommit.name()))).isNotNull();
diff --git a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
index c99e68b..4e84b3c 100644
--- a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
+++ b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
@@ -1951,16 +1951,17 @@
     Change change1 = insert(repo, newChange(repo));
     Change change2 = insert(repo, newChange(repo));
 
-    HashtagsInput in = new HashtagsInput();
-    in.add = ImmutableSet.of("foo");
-    gApi.changes().id(change1.getId().get()).setHashtags(in);
-
-    in.add = ImmutableSet.of("foo", "bar", "a tag", "ACamelCaseTag");
-    gApi.changes().id(change2.getId().get()).setHashtags(in);
-
+    addHashtags(change1.getId(), "foo", "aaa-bbb-ccc");
+    addHashtags(change2.getId(), "foo", "bar", "a tag", "ACamelCaseTag");
     return ImmutableList.of(change1, change2);
   }
 
+  private void addHashtags(Change.Id changeId, String... hashtags) throws Exception {
+    HashtagsInput in = new HashtagsInput();
+    in.add = ImmutableSet.copyOf(hashtags);
+    gApi.changes().id(changeId.get()).setHashtags(in);
+  }
+
   @Test
   public void byHashtag() throws Exception {
     List<Change> changes = setUpHashtagChanges();
@@ -1976,6 +1977,31 @@
   }
 
   @Test
+  public void byHashtagFullText() throws Exception {
+    assume().that(getSchema().hasField(ChangeField.FUZZY_HASHTAG)).isTrue();
+    List<Change> changes = setUpHashtagChanges();
+    assertQuery("inhashtag:foo", changes.get(1), changes.get(0));
+    assertQuery("inhashtag:bbb", changes.get(0));
+    assertQuery("inhashtag:tag", changes.get(1));
+  }
+
+  @Test
+  public void byHashtagRegex() throws Exception {
+    TestRepository<Repo> repo = createProject("repo");
+    Change change1 = insert(repo, newChange(repo));
+    Change change2 = insert(repo, newChange(repo));
+    Change change3 = insert(repo, newChange(repo));
+    addHashtags(change1.getId(), "feature1");
+    addHashtags(change1.getId(), "trending");
+    addHashtags(change2.getId(), "Cherrypick-feature1");
+    addHashtags(change3.getId(), "feature1-fixup");
+
+    assertQuery("inhashtag:^feature1.*", change3, change1);
+    assertQuery("inhashtag:{^.*feature1$}", change2, change1);
+    assertQuery("inhashtag:^trending.*", change1);
+  }
+
+  @Test
   public void byDefault() throws Exception {
     TestRepository<Repo> repo = createProject("repo");
 
diff --git a/package.json b/package.json
index 3c40690..f5eafee 100644
--- a/package.json
+++ b/package.json
@@ -3,24 +3,24 @@
   "version": "3.1.0-SNAPSHOT",
   "description": "Gerrit Code Review",
   "dependencies": {
-    "@bazel/rollup": "^3.2.3",
-    "@bazel/terser": "^3.2.3",
-    "@bazel/typescript": "^3.2.3"
+    "@bazel/rollup": "^3.4.0",
+    "@bazel/terser": "^3.4.0",
+    "@bazel/typescript": "^3.4.0"
   },
   "devDependencies": {
-    "@typescript-eslint/eslint-plugin": "^4.11.0",
-    "eslint": "^7.16.0",
+    "@typescript-eslint/eslint-plugin": "^4.22.0",
+    "eslint": "^7.24.0",
     "eslint-config-google": "^0.14.0",
-    "eslint-plugin-html": "^6.1.1",
+    "eslint-plugin-html": "^6.1.2",
     "eslint-plugin-import": "^2.22.1",
-    "eslint-plugin-jsdoc": "^30.7.9",
+    "eslint-plugin-jsdoc": "^32.3.0",
     "eslint-plugin-node": "^11.1.0",
-    "eslint-plugin-prettier": "^3.3.0",
-    "gts": "^3.0.3",
+    "eslint-plugin-prettier": "^3.4.0",
+    "gts": "^3.1.0",
     "polymer-cli": "^1.9.11",
-    "prettier": "2.0.5",
-    "rollup": "^2.3.4",
-    "terser": "^4.8.0",
+    "prettier": "2.2.1",
+    "rollup": "^2.45.2",
+    "terser": "^5.6.1",
     "typescript": "4.1.4"
   },
   "scripts": {
diff --git a/polygerrit-ui/app/api/checks.ts b/polygerrit-ui/app/api/checks.ts
index 3be34fe..f20eec8 100644
--- a/polygerrit-ui/app/api/checks.ts
+++ b/polygerrit-ui/app/api/checks.ts
@@ -223,6 +223,8 @@
   name: string;
   tooltip?: string;
   /**
+   * TODO: Maybe drop this property? Do we really need it?
+   *
    * Primary actions will get a more prominent treatment in the UI. For example
    * primary actions might be rendered as buttons versus just menu entries in
    * an overflow menu.
@@ -383,6 +385,8 @@
   url: string;
   tooltip?: string;
   /**
+   * TODO: Maybe drop this property? Do we really need it?
+   *
    * Primary links will get a more prominent treatment in the UI, e.g. being
    * always visible in the results table or also showing up in the change page
    * summary of checks.
@@ -391,8 +395,12 @@
   icon: LinkIcon;
 }
 
-// TBD: Add more ...
 export enum LinkIcon {
   EXTERNAL,
+  IMAGE,
+  HISTORY,
   DOWNLOAD,
+  DOWNLOAD_MOBILE,
+  HELP_PAGE,
+  REPORT_BUG,
 }
diff --git a/polygerrit-ui/app/api/diff.ts b/polygerrit-ui/app/api/diff.ts
index 11776d0..f7d5a59 100644
--- a/polygerrit-ui/app/api/diff.ts
+++ b/polygerrit-ui/app/api/diff.ts
@@ -251,6 +251,19 @@
   lineNum: LineNumber;
 }
 
+/** All types of button for expanding diff sections */
+export enum ContextButtonType {
+  ABOVE = 'above',
+  BELOW = 'below',
+  ALL = 'all',
+}
+
+/** Details to be externally accessed when expanding diffs */
+export declare interface DiffContextExpandedExternalDetail {
+  expandedLines: number;
+  buttonType: ContextButtonType;
+}
+
 export enum GrDiffLineType {
   ADD = 'add',
   BOTH = 'both',
@@ -285,7 +298,8 @@
   annotate(
     textElement: HTMLElement,
     lineNumberElement: HTMLElement,
-    line: GrDiffLine
+    line: GrDiffLine,
+    side: Side
   ): void;
 }
 
diff --git a/polygerrit-ui/app/constants/constants.ts b/polygerrit-ui/app/constants/constants.ts
index be502f7..363f6e5 100644
--- a/polygerrit-ui/app/constants/constants.ts
+++ b/polygerrit-ui/app/constants/constants.ts
@@ -54,6 +54,7 @@
   TAG_SET_ASSIGNEE = 'autogenerated:gerrit:setAssignee',
   TAG_UNSET_ASSIGNEE = 'autogenerated:gerrit:deleteAssignee',
   TAG_MERGED = 'autogenerated:gerrit:merged',
+  TAG_REVERT = 'autogenerated:gerrit:revert',
 }
 
 /**
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list_html.ts b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list_html.ts
index 7574f79..91863a9 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list_html.ts
@@ -67,9 +67,7 @@
       on-confirm="_handleCreateGroup"
       on-cancel="_handleCloseCreate"
     >
-      <div class="header" slot="header">
-        Create Group
-      </div>
+      <div class="header" slot="header">Create Group</div>
       <div class="main" slot="main">
         <gr-create-group-dialog
           has-new-group-name="{{_hasNewGroupName}}"
diff --git a/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog_html.ts b/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog_html.ts
index ce9ac9c..890d345 100644
--- a/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog_html.ts
@@ -37,9 +37,7 @@
         Do you really want to delete the following
         [[_computeItemName(itemType)]]?
       </label>
-      <div>
-        [[item]]
-      </div>
+      <div>[[item]]</div>
     </div>
   </gr-dialog>
 `;
diff --git a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_html.ts b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_html.ts
index 272cb09..47da237 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_html.ts
@@ -136,9 +136,7 @@
               <tr class="headerRow">
                 <th class="groupNameHeader">Group Name</th>
                 <th class="descriptionHeader">Description</th>
-                <th class="deleteIncludedHeader">
-                  Delete Group
-                </th>
+                <th class="deleteIncludedHeader">Delete Group</th>
               </tr>
             </tbody>
             <tbody>
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access-interfaces.ts b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access-interfaces.ts
index 40a1e0a..869a416 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access-interfaces.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access-interfaces.ts
@@ -72,9 +72,7 @@
   extends PermissionRuleInfo,
     PropertyTreeNode {}
 
-export type PermissionAccessSection = PermissionArrayItem<
-  EditableAccessSectionInfo
->;
+export type PermissionAccessSection = PermissionArrayItem<EditableAccessSectionInfo>;
 
 export interface NewlyAddedGroupInfo {
   name: string;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_html.ts b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_html.ts
index a77f1ae..f572ac3 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_html.ts
@@ -76,9 +76,7 @@
       on-confirm="_handleCreateChange"
       on-cancel="_handleCloseCreateChange"
     >
-      <div class="header" slot="header">
-        Create Change
-      </div>
+      <div class="header" slot="header">Create Change</div>
       <div class="main" slot="main">
         <gr-create-change-dialog
           id="createNewChangeModal"
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.ts b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.ts
index 9e68a24..7e6db64 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.ts
@@ -118,7 +118,7 @@
   _determineIfOwner(repo: RepoName) {
     return this.restApiService
       .getRepoAccess(repo)
-      .then(access => (this._isOwner = !!access && !!access[repo].is_owner));
+      .then(access => (this._isOwner = !!access && !!access[repo]?.is_owner));
   }
 
   _paramsChanged(params?: AppElementRepoParams) {
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_html.ts b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_html.ts
index 4435d3a..2ac32c0 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_html.ts
@@ -91,9 +91,7 @@
           <th class$="tagger topHeader [[_hideIfBranch(detailType)]]">
             Tagger
           </th>
-          <th class="repositoryBrowser topHeader">
-            Repository Browser
-          </th>
+          <th class="repositoryBrowser topHeader">Repository Browser</th>
           <th class="delete topHeader"></th>
         </tr>
         <tr id="loading" class$="loadingMsg [[computeLoadingClass(_loading)]]">
@@ -111,13 +109,9 @@
             <td
               class$="[[detailType]] revision [[_computeCanEditClass(item.ref, detailType, _isOwner)]]"
             >
-              <span class="revisionNoEditing">
-                [[item.revision]]
-              </span>
+              <span class="revisionNoEditing"> [[item.revision]] </span>
               <span class$="revisionEdit [[_computeEditingClass(_isEditing)]]">
-                <span class="revisionWithEditing">
-                  [[item.revision]]
-                </span>
+                <span class="revisionWithEditing"> [[item.revision]] </span>
                 <gr-button
                   link=""
                   on-click="_handleEditRevision"
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_html.ts b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_html.ts
index 20c72f9..e1a7f489 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_html.ts
@@ -104,9 +104,7 @@
       on-confirm="_handleCreateRepo"
       on-cancel="_handleCloseCreate"
     >
-      <div class="header" slot="header">
-        Create Repository
-      </div>
+      <div class="header" slot="header">Create Repository</div>
       <div class="main" slot="main">
         <gr-create-repo-dialog
           has-new-repo-name="{{_hasNewRepoName}}"
diff --git a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_html.ts b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_html.ts
index 1ca5636..b88eeaf 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_html.ts
@@ -50,9 +50,7 @@
       /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
     </style>
     <div class="info">
-      <h1 id="Title" class="heading-1">
-        [[repo]]
-      </h1>
+      <h1 id="Title" class="heading-1">[[repo]]</h1>
       <hr />
       <div>
         <a href$="[[_computeBrowseUrl(weblinks)]]"
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts
index 20941a61e..2869750 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts
@@ -36,7 +36,7 @@
 import {appContext} from '../../../services/app-context';
 import {truncatePath} from '../../../utils/path-list-util';
 import {changeStatuses} from '../../../utils/change-util';
-import {isServiceUser} from '../../../utils/account-util';
+import {isSelf, isServiceUser} from '../../../utils/account-util';
 import {customElement, property} from '@polymer/decorators';
 import {ReportingService} from '../../../services/gr-reporting/gr-reporting';
 import {
@@ -329,8 +329,8 @@
     );
     reviewers.sort((r1, r2) => {
       if (this.account) {
-        if (r1._account_id === this.account._account_id) return -1;
-        if (r2._account_id === this.account._account_id) return 1;
+        if (isSelf(r1, this.account)) return -1;
+        if (isSelf(r2, this.account)) return 1;
       }
       if (this._hasAttention(r1) && !this._hasAttention(r2)) return -1;
       if (this._hasAttention(r2) && !this._hasAttention(r1)) return 1;
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_html.ts b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_html.ts
index 360c34f..fac552a 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_html.ts
@@ -136,12 +136,8 @@
       on-click="_handleChangeClick"
     >
       <div class="container">
-        <div class="content">
-          [[change.subject]]
-        </div>
-        <div class="spacer">
-          [[change.subject]]
-        </div>
+        <div class="content">[[change.subject]]</div>
+        <div class="spacer">[[change.subject]]</div>
         <span>&nbsp;</span>
       </div>
     </a>
@@ -243,9 +239,7 @@
     class="cell branch"
     hidden$="[[isColumnHidden('Branch', visibleChangeTableColumns)]]"
   >
-    <a href$="[[_computeRepoBranchURL(change)]]">
-      [[change.branch]]
-    </a>
+    <a href$="[[_computeRepoBranchURL(change)]]"> [[change.branch]] </a>
     <template is="dom-if" if="[[change.topic]]">
       (<a href$="[[_computeTopicURL(change)]]"
         ><!--
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts
index 62cfcb4..2b79fe0 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts
@@ -28,7 +28,6 @@
 import {
   KeyboardShortcutMixin,
   Shortcut,
-  Modifier,
 } from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
 import {
   GerritNav,
@@ -53,7 +52,7 @@
 } from '../../../utils/attention-set-util';
 import {CustomKeyboardEvent} from '../../../types/events';
 import {fireEvent} from '../../../utils/event-util';
-import {windowLocationReload} from '../../../utils/dom-util';
+import {isShiftPressed, windowLocationReload} from '../../../utils/dom-util';
 import {ScrollMode} from '../../../constants/constants';
 
 const NUMBER_FIXED_COLUMNS = 3;
@@ -439,8 +438,7 @@
   _nextPage(e: CustomKeyboardEvent) {
     if (
       this.shouldSuppressKeyboardShortcut(e) ||
-      (this.modifierPressed(e) &&
-        !this.isModifierPressed(e, Modifier.SHIFT_KEY))
+      (this.modifierPressed(e) && !isShiftPressed(e))
     ) {
       return;
     }
@@ -452,8 +450,7 @@
   _prevPage(e: CustomKeyboardEvent) {
     if (
       this.shouldSuppressKeyboardShortcut(e) ||
-      (this.modifierPressed(e) &&
-        !this.isModifierPressed(e, Modifier.SHIFT_KEY))
+      (this.modifierPressed(e) && !isShiftPressed(e))
     ) {
       return;
     }
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.ts b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.ts
index a1c27dc..317d27f 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.ts
@@ -121,9 +121,7 @@
               items="[[_computeColumns(changeSection, visibleChangeTableColumns)]]"
               as="item"
             >
-              <td class$="[[_lowerCase(item)]]">
-                [[item]]
-              </td>
+              <td class$="[[_lowerCase(item)]]">[[item]]</td>
             </template>
             <template is="dom-repeat" items="[[labelNames]]" as="labelName">
               <td class="label" title$="[[labelName]]">
diff --git a/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help_html.ts b/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help_html.ts
index add7ca5..95a67af 100644
--- a/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help_html.ts
@@ -64,9 +64,7 @@
     <div id="circle">
       <iron-icon id="icon" icon="gr-icons:zeroState"></iron-icon>
     </div>
-    <p>
-      No outgoing changes yet
-    </p>
+    <p>No outgoing changes yet</p>
   </div>
   <div id="help">
     <h2 class="heading-3">Push your first change for code review</h2>
diff --git a/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog_html.ts b/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog_html.ts
index 9031738..d2f35d6 100644
--- a/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog_html.ts
@@ -37,26 +37,18 @@
       confirm-on-enter=""
       on-confirm="_handleClose"
     >
-      <div class="header" slot="header">
-        Create change commands
-      </div>
+      <div class="header" slot="header">Create change commands</div>
       <div class="main" slot="main">
         <ol>
           <li>
-            <p>
-              Make the changes to the files on your machine
-            </p>
+            <p>Make the changes to the files on your machine</p>
           </li>
           <li>
-            <p>
-              If you are making a new commit use
-            </p>
+            <p>If you are making a new commit use</p>
             <gr-shell-command
               command="[[_createNewCommitCommand]]"
             ></gr-shell-command>
-            <p>
-              Or to amend an existing commit use
-            </p>
+            <p>Or to amend an existing commit use</p>
             <gr-shell-command
               command="[[_amendExistingCommitCommand]]"
             ></gr-shell-command>
@@ -66,9 +58,7 @@
             </p>
           </li>
           <li>
-            <p>
-              Push the change for code review
-            </p>
+            <p>Push the change for code review</p>
             <gr-shell-command command="[[_pushCommand]]"></gr-shell-command>
           </li>
           <li>
diff --git a/polygerrit-ui/app/elements/change-list/gr-create-destination-dialog/gr-create-destination-dialog_html.ts b/polygerrit-ui/app/elements/change-list/gr-create-destination-dialog/gr-create-destination-dialog_html.ts
index 9155d9a..0aed75b 100644
--- a/polygerrit-ui/app/elements/change-list/gr-create-destination-dialog/gr-create-destination-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-create-destination-dialog/gr-create-destination-dialog_html.ts
@@ -25,17 +25,13 @@
       on-cancel="_handleClose"
       disabled="[[!_repoAndBranchSelected]]"
     >
-      <div class="header" slot="header">
-        Create change
-      </div>
+      <div class="header" slot="header">Create change</div>
       <div class="main" slot="main">
         <gr-repo-branch-picker
           repo="{{_repo}}"
           branch="{{_branch}}"
         ></gr-repo-branch-picker>
-        <p>
-          If you haven't done so, you will need to clone the repository.
-        </p>
+        <p>If you haven't done so, you will need to clone the repository.</p>
       </div>
     </gr-dialog>
   </gr-overlay>
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_html.ts b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_html.ts
index 730797c..fd23970 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_html.ts
@@ -92,9 +92,7 @@
             on-create-tap="_handleCreateChangeTap"
           ></gr-create-change-help>
         </template>
-        <template is="dom-if" if="[[!_showNewUserHelp]]">
-          No changes
-        </template>
+        <template is="dom-if" if="[[!_showNewUserHelp]]"> No changes </template>
       </div>
       <div id="emptyYourTurn" slot="empty-your-turn">
         <span>No changes need your attention &nbsp;&#x1f389;</span>
@@ -108,9 +106,7 @@
       on-confirm="_handleConfirmDelete"
       on-cancel="_closeConfirmDeleteOverlay"
     >
-      <div class="header" slot="header">
-        Delete comments
-      </div>
+      <div class="header" slot="header">Delete comments</div>
       <div class="main" slot="main">
         Are you sure you want to delete all your draft comments in closed
         changes? This action cannot be undone.
diff --git a/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header_html.ts b/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header_html.ts
index fafd38c..0dbec1c 100644
--- a/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header_html.ts
@@ -30,9 +30,7 @@
     /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
   </style>
   <div class="info">
-    <h1 class="heading-1">
-      [[repo]]
-    </h1>
+    <h1 class="heading-1">[[repo]]</h1>
     <hr />
     <div><span>Detail:</span> <a href$="[[_repoUrl]]">Repo settings</a></div>
     <span is="dom-if" if="[[_webLinks]]">
diff --git a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header_html.ts b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header_html.ts
index a8a6a56..1924a66 100644
--- a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header_html.ts
@@ -33,9 +33,7 @@
     aria-label="Account avatar"
   ></gr-avatar>
   <div class="info">
-    <h1 class="heading-1">
-      [[_computeHeading(_accountDetails)]]
-    </h1>
+    <h1 class="heading-1">[[_computeHeading(_accountDetails)]]</h1>
     <hr />
     <div class$="status [[_computeStatusClass(_status)]]">
       <span>Status:</span> [[_status]]
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
index 9199cea..db33344 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
@@ -339,7 +339,8 @@
 }
 
 @customElement('gr-change-actions')
-export class GrChangeActions extends PolymerElement
+export class GrChangeActions
+  extends PolymerElement
   implements GrChangeActionsElement {
   static get template() {
     return htmlTemplate;
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_html.ts b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_html.ts
index 71500ac..023e801 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_html.ts
@@ -90,6 +90,7 @@
           has-tooltip="[[_computeHasTooltip(action.title)]]"
           position-below="true"
           data-action-key$="[[action.__key]]"
+          class$="[[action.__key]]"
           data-action-type$="[[action.__type]]"
           data-label$="[[action.label]]"
           disabled$="[[_calculateDisabled(action, _hasKnownChainState)]]"
@@ -118,6 +119,7 @@
           has-tooltip="[[_computeHasTooltip(action.title)]]"
           position-below="true"
           data-action-key$="[[action.__key]]"
+          class$="[[action.__key]]"
           data-action-type$="[[action.__type]]"
           data-label$="[[action.label]]"
           disabled$="[[_calculateDisabled(action, _hasKnownChainState)]]"
@@ -226,9 +228,7 @@
       on-confirm="_handleCreateFollowUpChange"
       on-cancel="_handleCloseCreateFollowUpChange"
     >
-      <div class="header" slot="header">
-        Create Follow-Up Change
-      </div>
+      <div class="header" slot="header">Create Follow-Up Change</div>
       <div class="main" slot="main">
         <gr-create-change-dialog
           id="createFollowUpChange"
@@ -247,9 +247,7 @@
       on-cancel="_handleConfirmDialogCancel"
       on-confirm="_handleDeleteConfirm"
     >
-      <div class="header" slot="header">
-        Delete Change
-      </div>
+      <div class="header" slot="header">Delete Change</div>
       <div class="main" slot="main">
         Do you really want to delete the change?
       </div>
@@ -262,12 +260,8 @@
       on-cancel="_handleConfirmDialogCancel"
       on-confirm="_handleDeleteEditConfirm"
     >
-      <div class="header" slot="header">
-        Delete Change Edit
-      </div>
-      <div class="main" slot="main">
-        Do you really want to delete the edit?
-      </div>
+      <div class="header" slot="header">Delete Change Edit</div>
+      <div class="main" slot="main">Do you really want to delete the edit?</div>
     </gr-dialog>
   </gr-overlay>
 `;
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.ts b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.ts
index d5a917f..e8569ec 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.ts
@@ -85,6 +85,10 @@
   AutocompleteQuery,
   AutocompleteSuggestion,
 } from '../../shared/gr-autocomplete/gr-autocomplete';
+import {
+  getRevertCommitHash,
+  isRevertCreated,
+} from '../../../utils/message-util';
 
 const HASHTAG_ADD_MESSAGE = 'Add Hashtag';
 
@@ -292,6 +296,10 @@
     return weblinks.length ? weblinks : undefined;
   }
 
+  _isChangeMerged(change?: ParsedChangeInfo) {
+    return change?.status === ChangeStatus.MERGED;
+  }
+
   _isAssigneeEnabled(serverConfig?: ServerInfo) {
     return !!serverConfig?.change?.enable_assignee;
   }
@@ -583,6 +591,16 @@
     return rev.commit;
   }
 
+  _showRevertCreatedAs(change?: ParsedChangeInfo) {
+    if (!change) return false;
+    return isRevertCreated(change.messages);
+  }
+
+  _computeRevertCommit(change?: ParsedChangeInfo) {
+    if (!change) return undefined;
+    return {commit: getRevertCommitHash(change.messages)};
+  }
+
   _computeShowAllLabelText(showAllSections: boolean) {
     if (showAllSections) {
       return 'Show less';
@@ -711,7 +729,9 @@
           .map(change => change.topic)
           .filter(notUndefined)
           .filter(unique)
-          .map(topic => ({name: topic, value: topic}))
+          .map(topic => {
+            return {name: topic, value: topic};
+          })
       );
   }
 }
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_html.ts b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_html.ts
index 2864578..9db5533 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_html.ts
@@ -246,6 +246,7 @@
           change="{{change}}"
           mutable="[[_mutable]]"
           reviewers-only=""
+          account="[[account]]"
           server-config="[[serverConfig]]"
         ></gr-reviewer-list>
       </span>
@@ -259,6 +260,7 @@
           change="{{change}}"
           mutable="[[_mutable]]"
           ccs-only=""
+          account="[[account]]"
           server-config="[[serverConfig]]"
         ></gr-reviewer-list>
       </span>
@@ -339,18 +341,34 @@
         </ol>
       </span>
     </section>
-    <section
-      class$="[[_computeDisplayState(_showAllSections, change, _SECTION.MERGED_AS)]]"
-    >
-      <span class="title">Merged As</span>
-      <span class="value">
-        <gr-commit-info
-          change="[[change]]"
-          commit-info="[[_computeMergedCommitInfo(change.current_revision, change.revisions)]]"
-          server-config="[[serverConfig]]"
-        ></gr-commit-info>
-      </span>
-    </section>
+    <template is="dom-if" if="[[_isChangeMerged(change)]]">
+      <section
+        class$="[[_computeDisplayState(_showAllSections, change, _SECTION.MERGED_AS)]]"
+      >
+        <span class="title">Merged As</span>
+        <span class="value">
+          <gr-commit-info
+            change="[[change]]"
+            commit-info="[[_computeMergedCommitInfo(change.current_revision, change.revisions)]]"
+            server-config="[[serverConfig]]"
+          ></gr-commit-info>
+        </span>
+      </section>
+    </template>
+    <template is="dom-if" if="[[_showRevertCreatedAs(change)]]">
+      <section
+        class$="[[_computeDisplayState(_showAllSections, change, _SECTION.REVERT_CREATED_AS)]]"
+      >
+        <span class="title">Revert Created As</span>
+        <span class="value">
+          <gr-commit-info
+            change="[[change]]"
+            commit-info="[[_computeRevertCommit(change)]]"
+            server-config="[[serverConfig]]"
+          ></gr-commit-info>
+        </span>
+      </section>
+    </template>
     <section
       class$="topic [[_computeDisplayState(_showAllSections, change, _SECTION.TOPIC)]]"
     >
diff --git a/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary.ts b/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary.ts
index 94324f3d..c4db747 100644
--- a/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary.ts
@@ -23,9 +23,9 @@
 import {
   CheckResult,
   CheckRun,
-  allRuns$,
   aPluginHasRegistered$,
   someProvidersAreLoading$,
+  allRunsLatest$,
 } from '../../../services/checks/checks-model';
 import {Category, Link, RunStatus} from '../../../api/checks';
 import {fireShowPrimaryTab} from '../../../utils/event-util';
@@ -289,7 +289,7 @@
 
   constructor() {
     super();
-    this.subscribe('runs', allRuns$);
+    this.subscribe('runs', allRunsLatest$);
     this.subscribe('showChecksSummary', aPluginHasRegistered$);
     this.subscribe('someProvidersAreLoading', someProvidersAreLoading$);
   }
@@ -368,9 +368,10 @@
       this.detailsQuota -= runs.length;
       return runs.map(run => {
         const allLinks = resultFilter(run)
-          .reduce((links, result) => {
-            return links.concat(result.links ?? []);
-          }, [] as Link[])
+          .reduce(
+            (links, result) => links.concat(result.links ?? []),
+            [] as Link[]
+          )
           .filter(link => link.primary);
         const links = allLinks.length === 1 ? allLinks : [];
         const text = `${run.checkName}`;
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
index 8f8b2b8..34839e6 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
@@ -780,9 +780,9 @@
   ) {
     if (!paperTabs) return;
     const {activeTabName, activeTabIndex, scrollIntoView} = activeDetails;
-    const tabs = paperTabs.querySelectorAll('paper-tab') as NodeListOf<
-      HTMLElement
-    >;
+    const tabs = paperTabs.querySelectorAll(
+      'paper-tab'
+    ) as NodeListOf<HTMLElement>;
     let activeIndex = -1;
     if (activeTabIndex !== undefined) {
       activeIndex = activeTabIndex;
@@ -1572,17 +1572,6 @@
     return GerritNav.getUrlForChange(change);
   }
 
-  _computeShowCommitInfo(
-    changeStatuses: string[],
-    current_revision: RevisionInfo
-  ) {
-    return (
-      changeStatuses.length === 1 &&
-      changeStatuses[0] === 'Merged' &&
-      current_revision
-    );
-  }
-
   _computeChangeIdClass(displayChangeId: string) {
     return displayChangeId === CHANGE_ID_ERROR.MISMATCH ? 'warning' : '';
   }
@@ -2681,9 +2670,9 @@
 
   _handleFileActionTap(e: CustomEvent<{path: string; action: string}>) {
     e.preventDefault();
-    const controls = this.$.fileListHeader.shadowRoot!.querySelector<
-      GrEditControls
-    >('#editControls');
+    const controls = this.$.fileListHeader.shadowRoot!.querySelector<GrEditControls>(
+      '#editControls'
+    );
     if (!controls) throw new Error('Missing edit controls');
     assertIsDefined(this._change, '_change');
     if (!this._patchRange)
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.ts
index ccca679..bb99529 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.ts
@@ -368,6 +368,7 @@
           <div class="changeStatuses">
             <template is="dom-repeat" items="[[_changeStatuses]]" as="status">
               <gr-change-status
+                change="[[_change]]"
                 max-width="100"
                 status="[[status]]"
               ></gr-change-status>
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
index 95aa20e..d1f9ff0 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
@@ -112,7 +112,9 @@
 suite('gr-change-view tests', () => {
   let element: GrChangeView;
 
-  let navigateToChangeStub: SinonStubbedMember<typeof GerritNav.navigateToChange>;
+  let navigateToChangeStub: SinonStubbedMember<
+    typeof GerritNav.navigateToChange
+  >;
 
   suiteSetup(() => {
     const kb = TestKeyboardShortcutBinder.push();
@@ -903,7 +905,9 @@
   });
 
   suite('reloading drafts', () => {
-    let reloadStub: SinonStubbedMember<typeof element.$.commentAPI.reloadDrafts>;
+    let reloadStub: SinonStubbedMember<
+      typeof element.$.commentAPI.reloadDrafts
+    >;
     const drafts: {[path: string]: UIDraft[]} = {
       'testfile.txt': [
         {
@@ -1659,9 +1663,8 @@
       Promise.resolve(new Response(null, {status: 500}))
     );
 
-    const mockEvent = (content: string) => {
-      return new CustomEvent('', {detail: {content}});
-    };
+    const mockEvent = (content: string) =>
+      new CustomEvent('', {detail: {content}});
 
     element._handleCommitMessageSave(mockEvent('test \n  test '));
     assert.equal(putStub.lastCall.args[1], 'test\n  test');
@@ -2176,7 +2179,9 @@
   });
 
   suite('related changes expand/collapse', () => {
-    let updateHeightSpy: SinonSpyMember<typeof element._updateRelatedChangeMaxHeight>;
+    let updateHeightSpy: SinonSpyMember<
+      typeof element._updateRelatedChangeMaxHeight
+    >;
     setup(() => {
       updateHeightSpy = sinon.spy(element, '_updateRelatedChangeMaxHeight');
     });
@@ -2189,9 +2194,9 @@
       sinon.stub(element, '_getOffsetHeight').callsFake(() => 50);
       sinon.stub(element, '_getScrollHeight').callsFake(() => 60);
       sinon.stub(element, '_getLineHeight').callsFake(() => 5);
-      sinon.stub(window, 'matchMedia').callsFake(() => {
-        return {matches: true} as MediaQueryList;
-      });
+      sinon
+        .stub(window, 'matchMedia')
+        .callsFake(() => ({matches: true} as MediaQueryList));
       const relatedChanges = element.shadowRoot!.querySelector(
         '#relatedChanges'
       ) as GrRelatedChangesList;
@@ -2208,9 +2213,9 @@
       sinon.stub(element, '_getOffsetHeight').callsFake(() => 50);
       sinon.stub(element, '_getScrollHeight').callsFake(() => 40);
       sinon.stub(element, '_getLineHeight').callsFake(() => 5);
-      sinon.stub(window, 'matchMedia').callsFake(() => {
-        return {matches: true} as MediaQueryList;
-      });
+      sinon
+        .stub(window, 'matchMedia')
+        .callsFake(() => ({matches: true} as MediaQueryList));
       const relatedChanges = element.shadowRoot!.querySelector(
         '#relatedChanges'
       ) as GrRelatedChangesList;
@@ -2221,9 +2226,9 @@
 
     test('relatedChangesToggle functions', () => {
       sinon.stub(element, '_getOffsetHeight').callsFake(() => 50);
-      sinon.stub(window, 'matchMedia').callsFake(() => {
-        return {matches: false} as MediaQueryList;
-      });
+      sinon
+        .stub(window, 'matchMedia')
+        .callsFake(() => ({matches: false} as MediaQueryList));
       assert.isTrue(element._relatedChangesCollapsed);
       const relatedChangesToggleButton = element.shadowRoot!.querySelector(
         '#relatedChangesToggleButton'
@@ -2240,9 +2245,9 @@
     test('_updateRelatedChangeMaxHeight without commit toggle', () => {
       sinon.stub(element, '_getOffsetHeight').callsFake(() => 50);
       sinon.stub(element, '_getLineHeight').callsFake(() => 12);
-      sinon.stub(window, 'matchMedia').callsFake(() => {
-        return {matches: false} as MediaQueryList;
-      });
+      sinon
+        .stub(window, 'matchMedia')
+        .callsFake(() => ({matches: false} as MediaQueryList));
 
       // 50 (existing height) - 30 (extra height) = 20 (adjusted height).
       // 20 (max existing height)  % 12 (line height) = 6 (remainder).
@@ -2257,9 +2262,9 @@
       element._latestCommitMessage = _.times(31, String).join('\n');
       sinon.stub(element, '_getOffsetHeight').callsFake(() => 50);
       sinon.stub(element, '_getLineHeight').callsFake(() => 12);
-      sinon.stub(window, 'matchMedia').callsFake(() => {
-        return {matches: false} as MediaQueryList;
-      });
+      sinon
+        .stub(window, 'matchMedia')
+        .callsFake(() => ({matches: false} as MediaQueryList));
 
       // 50 (existing height) % 12 (line height) = 2 (remainder).
       // 50 (existing height)  - 2 (remainder) = 48 (max height to set).
@@ -2276,9 +2281,9 @@
       element._latestCommitMessage = _.times(31, String).join('\n');
       sinon.stub(element, '_getOffsetHeight').callsFake(() => 50);
       sinon.stub(element, '_getLineHeight').callsFake(() => 12);
-      sinon.stub(window, 'matchMedia').callsFake(() => {
-        return {matches: true} as MediaQueryList;
-      });
+      sinon
+        .stub(window, 'matchMedia')
+        .callsFake(() => ({matches: true} as MediaQueryList));
 
       element._updateRelatedChangeMaxHeight();
 
@@ -2308,7 +2313,9 @@
 
     suite('update checks', () => {
       let clock: SinonFakeTimers;
-      let startUpdateCheckTimerSpy: SinonSpyMember<typeof element._startUpdateCheckTimer>;
+      let startUpdateCheckTimerSpy: SinonSpyMember<
+        typeof element._startUpdateCheckTimer
+      >;
       setup(() => {
         clock = sinon.useFakeTimers();
         startUpdateCheckTimerSpy = sinon.spy(element, '_startUpdateCheckTimer');
diff --git a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.ts b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.ts
index 3ba12b43..cc2f650 100644
--- a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.ts
+++ b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.ts
@@ -81,6 +81,18 @@
     });
   }
 
+  computeCommitLink(
+    webLink?: string,
+    change?: ChangeInfo,
+    commitInfo?: CommitInfo,
+    serverConfig?: ServerInfo
+  ) {
+    if (webLink) return webLink;
+    const hash = this._computeShortHash(change, commitInfo, serverConfig);
+    if (hash === undefined) return '';
+    return GerritNav.getUrlForSearchQuery(hash);
+  }
+
   _computeShortHash(
     change?: ChangeInfo,
     commitInfo?: CommitInfo,
@@ -90,7 +102,7 @@
       return '';
     }
 
-    const {name} = this._getWeblink(change, commitInfo, serverConfig) || {};
-    return name;
+    const weblink = this._getWeblink(change, commitInfo, serverConfig);
+    return weblink?.name ?? '';
   }
 }
diff --git a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info_html.ts b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info_html.ts
index df0bb4a..65ca8b5 100644
--- a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info_html.ts
@@ -24,14 +24,12 @@
     }
   </style>
   <div class="container">
-    <template is="dom-if" if="[[_showWebLink]]">
-      <a target="_blank" rel="noopener" href$="[[_webLink]]"
-        >[[_computeShortHash(change, commitInfo, serverConfig)]]</a
-      >
-    </template>
-    <template is="dom-if" if="[[!_showWebLink]]">
-      [[_computeShortHash(change, commitInfo, serverConfig)]]
-    </template>
+    <a
+      target="_blank"
+      rel="noopener"
+      href$="[[computeCommitLink(_webLink, change, commitInfo, serverConfig)]]"
+      >[[_computeShortHash(change, commitInfo, serverConfig)]]</a
+    >
     <gr-copy-clipboard
       has-tooltip=""
       button-title="Copy full SHA to clipboard"
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_html.ts
index 6c0099e..d42f7e5 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_html.ts
@@ -120,9 +120,7 @@
         </div></template
       >
 
-      <label for="branchInput">
-        Cherry Pick to branch
-      </label>
+      <label for="branchInput"> Cherry Pick to branch </label>
       <gr-autocomplete
         id="branchInput"
         text="{{branch}}"
@@ -153,9 +151,7 @@
             bind-value="{{baseCommit}}"
           />
         </iron-input>
-        <label for="messageInput">
-          Cherry Pick Commit Message
-        </label>
+        <label for="messageInput"> Cherry Pick Commit Message </label>
       </template>
       <template
         is="dom-if"
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_html.ts
index de75a39..7c3c719 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_html.ts
@@ -56,9 +56,7 @@
       <p class="warning">
         Warning: moving a change will not change its parents.
       </p>
-      <label for="branchInput">
-        Move change to branch
-      </label>
+      <label for="branchInput"> Move change to branch </label>
       <gr-autocomplete
         id="branchInput"
         text="{{branch}}"
@@ -66,9 +64,7 @@
         placeholder="Destination branch"
       >
       </gr-autocomplete>
-      <label for="messageInput">
-        Move Change Message
-      </label>
+      <label for="messageInput"> Move Change Message </label>
       <iron-autogrow-textarea
         id="messageInput"
         class="message"
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_html.ts
index 7d28de6..6def4a5 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_html.ts
@@ -108,9 +108,7 @@
         />
         <label id="rebaseOnOtherLabel" for="rebaseOnOtherInput">
           Rebase on a specific change, ref, or commit
-          <span hidden$="[[!hasParent]]">
-            (breaks relation chain)
-          </span>
+          <span hidden$="[[!hasParent]]"> (breaks relation chain) </span>
         </label>
       </div>
       <div class="parentRevisionContainer">
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_html.ts
index a4e3e96..17647ad 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_html.ts
@@ -53,9 +53,7 @@
     on-confirm="_handleConfirmTap"
     on-cancel="_handleCancelTap"
   >
-    <div class="header" slot="header">
-      Revert Merged Change
-    </div>
+    <div class="header" slot="header">Revert Merged Change</div>
     <div class="main" slot="main">
       <div class="error" hidden$="[[!_showErrorMessage]]">
         <span> A reason is required </span>
@@ -87,9 +85,7 @@
         </div></template
       >
       <gr-endpoint-decorator name="confirm-revert-change">
-        <label for="messageInput">
-          Revert Commit Message
-        </label>
+        <label for="messageInput"> Revert Commit Message </label>
         <iron-autogrow-textarea
           id="messageInput"
           class="message"
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog_html.ts
index 49a9c70..48bd796 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-submission-dialog/gr-confirm-revert-submission-dialog_html.ts
@@ -45,9 +45,7 @@
   >
     <div class="header" slot="header">Revert Submission</div>
     <div class="main" slot="main">
-      <label for="messageInput">
-        Revert Commit Message
-      </label>
+      <label for="messageInput"> Revert Commit Message </label>
       <iron-autogrow-textarea
         id="messageInput"
         class="message"
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog_html.ts
index 29b3752..e4662da 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog_html.ts
@@ -44,9 +44,7 @@
     on-confirm="_handleConfirmTap"
   >
     <template is="dom-if" if="[[_initialised]]">
-      <div class="header" slot="header">
-        [[action.label]]
-      </div>
+      <div class="header" slot="header">[[action.label]]</div>
       <div class="main" slot="main">
         <gr-endpoint-decorator name="confirm-submit-change">
           <p>Ready to submit “<strong>[[change.subject]]</strong>”?</p>
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
index e94f67e..e22253b 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
@@ -24,7 +24,6 @@
 import '../gr-commit-info/gr-commit-info';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-file-list-header_html';
-import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
 import {FilesExpandedState} from '../gr-file-list-constants';
 import {GerritNav} from '../../core/gr-navigation/gr-navigation';
 import {computeLatestPatchNum, PatchSet} from '../../../utils/patch-set-util';
@@ -63,7 +62,7 @@
 }
 
 @customElement('gr-file-list-header')
-export class GrFileListHeader extends KeyboardShortcutMixin(PolymerElement) {
+export class GrFileListHeader extends PolymerElement {
   static get template() {
     return htmlTemplate;
   }
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 4b5525a..fc48679 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
@@ -33,7 +33,6 @@
 import {asyncForeach, debounce, DelayedTask} from '../../../utils/async-util';
 import {
   KeyboardShortcutMixin,
-  Modifier,
   Shortcut,
 } from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
 import {FilesExpandedState} from '../gr-file-list-constants';
@@ -47,7 +46,12 @@
   ScrollMode,
   SpecialFilePath,
 } from '../../../constants/constants';
-import {descendedFromClass, toggleClass} from '../../../utils/dom-util';
+import {
+  descendedFromClass,
+  getKeyboardEvent,
+  isShiftPressed,
+  toggleClass,
+} from '../../../utils/dom-util';
 import {
   addUnmodifiedFiles,
   computeDisplayPath,
@@ -924,7 +928,7 @@
       this._displayLine = true;
     } else {
       // Down key
-      if (this.getKeyboardEvent(e).keyCode === 40) {
+      if (getKeyboardEvent(e).keyCode === 40) {
         return;
       }
       e.preventDefault();
@@ -944,7 +948,7 @@
       this._displayLine = true;
     } else {
       // Up key
-      if (this.getKeyboardEvent(e).keyCode === 38) {
+      if (getKeyboardEvent(e).keyCode === 38) {
         return;
       }
       e.preventDefault();
@@ -964,10 +968,7 @@
 
   _handleOpenLastFile(e: CustomKeyboardEvent) {
     // Check for meta key to avoid overriding native chrome shortcut.
-    if (
-      this.shouldSuppressKeyboardShortcut(e) ||
-      this.getKeyboardEvent(e).metaKey
-    ) {
+    if (this.shouldSuppressKeyboardShortcut(e) || getKeyboardEvent(e).metaKey) {
       return;
     }
 
@@ -977,10 +978,7 @@
 
   _handleOpenFirstFile(e: CustomKeyboardEvent) {
     // Check for meta key to avoid overriding native chrome shortcut.
-    if (
-      this.shouldSuppressKeyboardShortcut(e) ||
-      this.getKeyboardEvent(e).metaKey
-    ) {
+    if (this.shouldSuppressKeyboardShortcut(e) || getKeyboardEvent(e).metaKey) {
       return;
     }
 
@@ -1005,15 +1003,14 @@
   _handleNextChunk(e: CustomKeyboardEvent) {
     if (
       this.shouldSuppressKeyboardShortcut(e) ||
-      (this.modifierPressed(e) &&
-        !this.isModifierPressed(e, Modifier.SHIFT_KEY)) ||
+      (this.modifierPressed(e) && !isShiftPressed(e)) ||
       this._noDiffsExpanded()
     ) {
       return;
     }
 
     e.preventDefault();
-    if (this.isModifierPressed(e, Modifier.SHIFT_KEY)) {
+    if (isShiftPressed(e)) {
       this.$.diffCursor.moveToNextCommentThread();
     } else {
       this.$.diffCursor.moveToNextChunk();
@@ -1023,15 +1020,14 @@
   _handlePrevChunk(e: CustomKeyboardEvent) {
     if (
       this.shouldSuppressKeyboardShortcut(e) ||
-      (this.modifierPressed(e) &&
-        !this.isModifierPressed(e, Modifier.SHIFT_KEY)) ||
+      (this.modifierPressed(e) && !isShiftPressed(e)) ||
       this._noDiffsExpanded()
     ) {
       return;
     }
 
     e.preventDefault();
-    if (this.isModifierPressed(e, Modifier.SHIFT_KEY)) {
+    if (isShiftPressed(e)) {
       this.$.diffCursor.moveToPreviousCommentThread();
     } else {
       this.$.diffCursor.moveToPreviousChunk();
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.ts
index 79569bc..f458994 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.ts
@@ -270,9 +270,7 @@
             [[_pendingConfirmationDetails.group.name]]
           </span>
           has
-          <span class="groupSize">
-            [[_pendingConfirmationDetails.count]]
-          </span>
+          <span class="groupSize"> [[_pendingConfirmationDetails.count]] </span>
           members.
           <br />
           Are you sure you want to add them all?
diff --git a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.ts b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.ts
index 817dc93..1fcc332 100644
--- a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.ts
@@ -20,7 +20,7 @@
 import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-reviewer-list_html';
-import {isServiceUser} from '../../../utils/account-util';
+import {isSelf, isServiceUser} from '../../../utils/account-util';
 import {hasAttention} from '../../../utils/attention-set-util';
 import {customElement, property, computed, observe} from '@polymer/decorators';
 import {
@@ -33,6 +33,7 @@
   AccountId,
   DetailedLabelInfo,
   EmailAddress,
+  AccountDetailInfo,
 } from '../../../types/common';
 import {PolymerDeepPropertyChange} from '@polymer/polymer/interfaces';
 import {GrAccountChip} from '../../shared/gr-account-chip/gr-account-chip';
@@ -58,6 +59,9 @@
   change?: ChangeInfo;
 
   @property({type: Object})
+  account?: AccountDetailInfo;
+
+  @property({type: Object})
   serverConfig?: ServerInfo;
 
   @property({type: Boolean, reflectToAttribute: true})
@@ -241,10 +245,15 @@
     this._reviewers = result
       .filter(reviewer => reviewer._account_id !== owner._account_id)
       // Sort order:
-      // 1. Human users in the attention set.
-      // 2. Other human users.
-      // 3. Service users.
+      // 1. The user themselves
+      // 2. Human users in the attention set.
+      // 3. Other human users.
+      // 4. Service users.
       .sort((r1, r2) => {
+        if (this.account) {
+          if (isSelf(r1, this.account)) return -1;
+          if (isSelf(r2, this.account)) return 1;
+        }
         const a1 = hasAttention(serverConfig, r1, this.change!) ? 1 : 0;
         const a2 = hasAttention(serverConfig, r2, this.change!) ? 1 : 0;
         const s1 = isServiceUser(r1) ? -2 : 0;
@@ -331,3 +340,9 @@
     return this.restApiService.removeChangeReviewer(this.change._number, id);
   }
 }
+
+declare global {
+  interface HTMLElementTagNameMap {
+    'gr-reviewer-list': GrReviewerList;
+  }
+}
diff --git a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.js b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.js
deleted file mode 100644
index 83b7794..0000000
--- a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.js
+++ /dev/null
@@ -1,399 +0,0 @@
-/**
- * @license
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import '../../../test/common-test-setup-karma.js';
-import './gr-reviewer-list.js';
-import {stubRestApi} from '../../../test/test-utils.js';
-
-const basicFixture = fixtureFromElement('gr-reviewer-list');
-
-suite('gr-reviewer-list tests', () => {
-  let element;
-
-  setup(() => {
-    element = basicFixture.instantiate();
-    element.serverConfig = {};
-
-    stubRestApi('removeChangeReviewer').returns(Promise.resolve({ok: true}));
-  });
-
-  test('controls hidden on immutable element', () => {
-    flush();
-    element.mutable = false;
-    assert.isTrue(element.shadowRoot
-        .querySelector('.controlsContainer').hasAttribute('hidden'));
-    element.mutable = true;
-    assert.isFalse(element.shadowRoot
-        .querySelector('.controlsContainer').hasAttribute('hidden'));
-  });
-
-  test('add reviewer button opens reply dialog', done => {
-    element.addEventListener('show-reply-dialog', () => {
-      done();
-    });
-    flush();
-    MockInteractions.tap(element.shadowRoot
-        .querySelector('.addReviewer'));
-  });
-
-  test('only show remove for removable reviewers', () => {
-    element.mutable = true;
-    element.change = {
-      owner: {
-        _account_id: 1,
-      },
-      reviewers: {
-        REVIEWER: [
-          {
-            _account_id: 2,
-            name: 'Bojack Horseman',
-            email: 'SecretariatRulez96@hotmail.com',
-          },
-          {
-            _account_id: 3,
-            name: 'Pinky Penguin',
-          },
-        ],
-        CC: [
-          {
-            _account_id: 4,
-            name: 'Diane Nguyen',
-            email: 'macarthurfellow2B@juno.com',
-          },
-          {
-            email: 'test@e.mail',
-          },
-        ],
-      },
-      removable_reviewers: [
-        {
-          _account_id: 3,
-          name: 'Pinky Penguin',
-        },
-        {
-          _account_id: 4,
-          name: 'Diane Nguyen',
-          email: 'macarthurfellow2B@juno.com',
-        },
-        {
-          email: 'test@e.mail',
-        },
-      ],
-    };
-    flush();
-    const chips =
-        element.root.querySelectorAll('gr-account-chip');
-    assert.equal(chips.length, 4);
-
-    for (const el of Array.from(chips)) {
-      const accountID = el.account._account_id || el.account.email;
-      assert.ok(accountID);
-
-      const buttonEl = el.shadowRoot
-          .querySelector('gr-button');
-      assert.isNotNull(buttonEl);
-      if (accountID == 2) {
-        assert.isTrue(buttonEl.hasAttribute('hidden'));
-      } else {
-        assert.isFalse(buttonEl.hasAttribute('hidden'));
-      }
-    }
-  });
-
-  suite('_handleRemove', () => {
-    let removeReviewerStub;
-    let reviewersChangedSpy;
-
-    const reviewerWithId = {
-      _account_id: 2,
-      name: 'Some name',
-    };
-
-    const reviewerWithIdAndEmail = {
-      _account_id: 4,
-      name: 'Some other name',
-      email: 'example@',
-    };
-
-    const reviewerWithEmailOnly = {
-      email: 'example2@example',
-    };
-
-    let chips;
-
-    setup(() => {
-      removeReviewerStub = sinon
-          .stub(element, '_removeReviewer')
-          .returns(Promise.resolve(new Response({status: 200})));
-      element.mutable = true;
-
-      const allReviewers = [
-        reviewerWithId,
-        reviewerWithIdAndEmail,
-        reviewerWithEmailOnly,
-      ];
-
-      element.change = {
-        owner: {
-          _account_id: 1,
-        },
-        reviewers: {
-          REVIEWER: allReviewers,
-        },
-        removable_reviewers: allReviewers,
-      };
-      flush();
-      chips = Array.from(element.root.querySelectorAll('gr-account-chip'));
-      assert.equal(chips.length, allReviewers.length);
-      reviewersChangedSpy = sinon.spy(element, '_reviewersChanged');
-    });
-
-    test('_handleRemove for account with accountId only', async () => {
-      const accountChip = chips.find(chip =>
-        chip.account._account_id === reviewerWithId._account_id
-      );
-      accountChip._handleRemoveTap(new MouseEvent('click'));
-      await flush();
-      assert.isTrue(removeReviewerStub.calledOnce);
-      assert.isTrue(removeReviewerStub.calledWith(reviewerWithId._account_id));
-      assert.isTrue(reviewersChangedSpy.called);
-      expect(element.change.reviewers.REVIEWER).to.have.deep.members([
-        reviewerWithIdAndEmail,
-        reviewerWithEmailOnly,
-      ]);
-    });
-
-    test('_handleRemove for account with accountId and email', async () => {
-      const accountChip = chips.find(chip =>
-        chip.account._account_id === reviewerWithIdAndEmail._account_id
-      );
-      accountChip._handleRemoveTap(new MouseEvent('click'));
-      await flush();
-      assert.isTrue(removeReviewerStub.calledOnce);
-      assert.isTrue(
-          removeReviewerStub.calledWith(reviewerWithIdAndEmail._account_id));
-      assert.isTrue(reviewersChangedSpy.called);
-      expect(element.change.reviewers.REVIEWER).to.have.deep.members([
-        reviewerWithId,
-        reviewerWithEmailOnly,
-      ]);
-    });
-
-    test('_handleRemove for account with email only', async () => {
-      const accountChip = chips.find(
-          chip => chip.account.email === reviewerWithEmailOnly.email
-      );
-      accountChip._handleRemoveTap(new MouseEvent('click'));
-      await flush();
-      assert.isTrue(removeReviewerStub.calledOnce);
-      assert.isTrue(removeReviewerStub.calledWith(reviewerWithEmailOnly.email));
-      assert.isTrue(reviewersChangedSpy.called);
-      expect(element.change.reviewers.REVIEWER).to.have.deep.members([
-        reviewerWithId,
-        reviewerWithIdAndEmail,
-      ]);
-    });
-  });
-
-  test('tracking reviewers and ccs', () => {
-    let counter = 0;
-    function makeAccount() {
-      return {_account_id: counter++};
-    }
-
-    const owner = makeAccount();
-    const reviewer = makeAccount();
-    const cc = makeAccount();
-    const reviewers = {
-      REMOVED: [makeAccount()],
-      REVIEWER: [owner, reviewer],
-      CC: [owner, cc],
-    };
-
-    element.ccsOnly = false;
-    element.reviewersOnly = false;
-    element.change = {
-      owner,
-      reviewers,
-    };
-    assert.deepEqual(element._reviewers, [reviewer, cc]);
-
-    element.reviewersOnly = true;
-    element.change = {
-      owner,
-      reviewers,
-    };
-    assert.deepEqual(element._reviewers, [reviewer]);
-
-    element.ccsOnly = true;
-    element.reviewersOnly = false;
-    element.change = {
-      owner,
-      reviewers,
-    };
-    assert.deepEqual(element._reviewers, [cc]);
-  });
-
-  test('_handleAddTap passes mode with event', () => {
-    const fireStub = sinon.stub(element, 'dispatchEvent');
-    const e = {preventDefault() {}};
-
-    element.ccsOnly = false;
-    element.reviewersOnly = false;
-    element._handleAddTap(e);
-    assert.equal(fireStub.lastCall.args[0].type, 'show-reply-dialog');
-    assert.deepEqual(fireStub.lastCall.args[0].detail, {value: {
-      reviewersOnly: false,
-      ccsOnly: false,
-    }});
-
-    element.reviewersOnly = true;
-    element._handleAddTap(e);
-    assert.equal(fireStub.lastCall.args[0].type, 'show-reply-dialog');
-    assert.deepEqual(
-        fireStub.lastCall.args[0].detail,
-        {value: {reviewersOnly: true, ccsOnly: false}});
-
-    element.ccsOnly = true;
-    element.reviewersOnly = false;
-    element._handleAddTap(e);
-    assert.equal(fireStub.lastCall.args[0].type, 'show-reply-dialog');
-    assert.deepEqual(fireStub.lastCall.args[0].detail,
-        {value: {ccsOnly: true, reviewersOnly: false}});
-  });
-
-  test('dont show all reviewers button with 4 reviewers', () => {
-    const reviewers = [];
-    element.maxReviewersDisplayed = 3;
-    for (let i = 0; i < 4; i++) {
-      reviewers.push(
-          {email: i+'reviewer@google.com', name: 'reviewer-' + i});
-    }
-    element.ccsOnly = true;
-
-    element.change = {
-      owner: {
-        _account_id: 1,
-      },
-      reviewers: {
-        CC: reviewers,
-      },
-    };
-    assert.equal(element._hiddenReviewerCount, 0);
-    assert.equal(element._displayedReviewers.length, 4);
-    assert.equal(element._reviewers.length, 4);
-    assert.isTrue(element.shadowRoot
-        .querySelector('.hiddenReviewers').hidden);
-  });
-
-  test('show all reviewers button with 9 reviewers', () => {
-    const reviewers = [];
-    for (let i = 0; i < 9; i++) {
-      reviewers.push(
-          {email: i+'reviewer@google.com', name: 'reviewer-' + i});
-    }
-    element.ccsOnly = true;
-
-    element.change = {
-      owner: {
-        _account_id: 1,
-      },
-      reviewers: {
-        CC: reviewers,
-      },
-    };
-    assert.equal(element._hiddenReviewerCount, 3);
-    assert.equal(element._displayedReviewers.length, 6);
-    assert.equal(element._reviewers.length, 9);
-    assert.isFalse(element.shadowRoot
-        .querySelector('.hiddenReviewers').hidden);
-  });
-
-  test('show all reviewers button', () => {
-    const reviewers = [];
-    for (let i = 0; i < 100; i++) {
-      reviewers.push(
-          {email: i+'reviewer@google.com', name: 'reviewer-' + i});
-    }
-    element.ccsOnly = true;
-
-    element.change = {
-      owner: {
-        _account_id: 1,
-      },
-      reviewers: {
-        CC: reviewers,
-      },
-    };
-    assert.equal(element._hiddenReviewerCount, 94);
-    assert.equal(element._displayedReviewers.length, 6);
-    assert.equal(element._reviewers.length, 100);
-    assert.isFalse(element.shadowRoot
-        .querySelector('.hiddenReviewers').hidden);
-
-    MockInteractions.tap(element.shadowRoot
-        .querySelector('.hiddenReviewers'));
-
-    assert.equal(element._hiddenReviewerCount, 0);
-    assert.equal(element._displayedReviewers.length, 100);
-    assert.equal(element._reviewers.length, 100);
-    assert.isTrue(element.shadowRoot
-        .querySelector('.hiddenReviewers').hidden);
-  });
-
-  test('votable labels', () => {
-    const change = {
-      labels: {
-        Foo: {
-          all: [{_account_id: 7, permitted_voting_range: {max: 2}}],
-        },
-        Bar: {
-          all: [{_account_id: 1, permitted_voting_range: {max: 1}},
-            {_account_id: 7, permitted_voting_range: {max: 1}}],
-        },
-        FooBar: {
-          all: [{_account_id: 7, value: 0}],
-        },
-      },
-      permitted_labels: {
-        Foo: ['-1', ' 0', '+1', '+2'],
-        FooBar: ['-1', ' 0'],
-      },
-    };
-    assert.strictEqual(
-        element._computeVoteableText({_account_id: 1}, change),
-        'Bar');
-    assert.strictEqual(
-        element._computeVoteableText({_account_id: 7}, change),
-        'Foo: +2, Bar, FooBar');
-    assert.strictEqual(
-        element._computeVoteableText({_account_id: 2}, change),
-        '');
-  });
-
-  test('fails gracefully when all is not included', () => {
-    const change = {
-      labels: {Foo: {}},
-      permitted_labels: {
-        Foo: ['-1', ' 0', '+1', '+2'],
-      },
-    };
-    assert.strictEqual(
-        element._computeVoteableText({_account_id: 1}, change), '');
-  });
-});
-
diff --git a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.ts b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.ts
new file mode 100644
index 0000000..0a709e1
--- /dev/null
+++ b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.ts
@@ -0,0 +1,477 @@
+/**
+ * @license
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import '../../../test/common-test-setup-karma';
+import './gr-reviewer-list';
+import {queryAndAssert, stubRestApi} from '../../../test/test-utils';
+import {GrReviewerList} from './gr-reviewer-list';
+import {
+  createAccountDetailWithId,
+  createChange,
+  createServerInfo,
+} from '../../../test/test-data-generators';
+import {tap} from '@polymer/iron-test-helpers/mock-interactions';
+import {GrButton} from '../../shared/gr-button/gr-button';
+import {AccountId, EmailAddress} from '../../../types/common';
+import {GrAccountChip} from '../../shared/gr-account-chip/gr-account-chip';
+
+const basicFixture = fixtureFromElement('gr-reviewer-list');
+
+suite('gr-reviewer-list tests', () => {
+  let element: GrReviewerList;
+
+  setup(() => {
+    element = basicFixture.instantiate();
+    element.serverConfig = createServerInfo();
+
+    stubRestApi('removeChangeReviewer').returns(
+      Promise.resolve({...new Response(), ok: true})
+    );
+  });
+
+  test('controls hidden on immutable element', () => {
+    flush();
+    element.mutable = false;
+    assert.isTrue(
+      queryAndAssert(element, '.controlsContainer').hasAttribute('hidden')
+    );
+    element.mutable = true;
+    assert.isFalse(
+      queryAndAssert(element, '.controlsContainer').hasAttribute('hidden')
+    );
+  });
+
+  test('add reviewer button opens reply dialog', done => {
+    element.addEventListener('show-reply-dialog', () => {
+      done();
+    });
+    flush();
+    tap(queryAndAssert(element, '.addReviewer'));
+  });
+
+  test('only show remove for removable reviewers', () => {
+    element.mutable = true;
+    element.change = {
+      ...createChange(),
+      owner: {
+        ...createAccountDetailWithId(1),
+      },
+      reviewers: {
+        REVIEWER: [
+          {
+            ...createAccountDetailWithId(2),
+            name: 'Bojack Horseman',
+            email: 'SecretariatRulez96@hotmail.com' as EmailAddress,
+          },
+          {
+            _account_id: 3 as AccountId,
+            name: 'Pinky Penguin',
+          },
+        ],
+        CC: [
+          {
+            ...createAccountDetailWithId(4),
+            name: 'Diane Nguyen',
+            email: 'macarthurfellow2B@juno.com' as EmailAddress,
+          },
+          {
+            email: 'test@e.mail' as EmailAddress,
+          },
+        ],
+      },
+      removable_reviewers: [
+        {
+          _account_id: 3 as AccountId,
+          name: 'Pinky Penguin',
+        },
+        {
+          ...createAccountDetailWithId(4),
+          name: 'Diane Nguyen',
+          email: 'macarthurfellow2B@juno.com' as EmailAddress,
+        },
+        {
+          email: 'test@e.mail' as EmailAddress,
+        },
+      ],
+    };
+    flush();
+    const chips = element.root!.querySelectorAll('gr-account-chip');
+    assert.equal(chips.length, 4);
+
+    for (const el of Array.from(chips)) {
+      const accountID = el.account!._account_id || el.account!.email;
+      assert.ok(accountID);
+
+      const buttonEl = queryAndAssert(el, 'gr-button');
+      if (accountID === 2) {
+        assert.isTrue(buttonEl.hasAttribute('hidden'));
+      } else {
+        assert.isFalse(buttonEl.hasAttribute('hidden'));
+      }
+    }
+  });
+
+  suite('_handleRemove', () => {
+    let removeReviewerStub: sinon.SinonStub;
+    let reviewersChangedSpy: sinon.SinonSpy;
+
+    const reviewerWithId = {
+      ...createAccountDetailWithId(2),
+      name: 'Some name',
+    };
+
+    const reviewerWithIdAndEmail = {
+      ...createAccountDetailWithId(4),
+      name: 'Some other name',
+      email: 'example@' as EmailAddress,
+    };
+
+    const reviewerWithEmailOnly = {
+      email: 'example2@example' as EmailAddress,
+    };
+
+    let chips: GrAccountChip[];
+
+    setup(() => {
+      removeReviewerStub = sinon
+        .stub(element, '_removeReviewer')
+        .returns(Promise.resolve(new Response()));
+      element.mutable = true;
+
+      const allReviewers = [
+        reviewerWithId,
+        reviewerWithIdAndEmail,
+        reviewerWithEmailOnly,
+      ];
+
+      element.change = {
+        ...createChange(),
+        owner: {
+          ...createAccountDetailWithId(1),
+        },
+        reviewers: {
+          REVIEWER: allReviewers,
+        },
+        removable_reviewers: allReviewers,
+      };
+      flush();
+      chips = Array.from(element.root!.querySelectorAll('gr-account-chip'));
+      assert.equal(chips.length, allReviewers.length);
+      reviewersChangedSpy = sinon.spy(element, '_reviewersChanged');
+    });
+
+    test('_handleRemove for account with accountId only', async () => {
+      const accountChip = chips.find(
+        chip => chip.account!._account_id === reviewerWithId._account_id
+      );
+      accountChip!._handleRemoveTap(new MouseEvent('click'));
+      await flush();
+      assert.isTrue(removeReviewerStub.calledOnce);
+      assert.isTrue(removeReviewerStub.calledWith(reviewerWithId._account_id));
+      assert.isTrue(reviewersChangedSpy.called);
+      expect(element.change!.reviewers.REVIEWER).to.have.deep.members([
+        reviewerWithIdAndEmail,
+        reviewerWithEmailOnly,
+      ]);
+    });
+
+    test('_handleRemove for account with accountId and email', async () => {
+      const accountChip = chips.find(
+        chip => chip.account!._account_id === reviewerWithIdAndEmail._account_id
+      );
+      accountChip!._handleRemoveTap(new MouseEvent('click'));
+      await flush();
+      assert.isTrue(removeReviewerStub.calledOnce);
+      assert.isTrue(
+        removeReviewerStub.calledWith(reviewerWithIdAndEmail._account_id)
+      );
+      assert.isTrue(reviewersChangedSpy.called);
+      expect(element.change!.reviewers.REVIEWER).to.have.deep.members([
+        reviewerWithId,
+        reviewerWithEmailOnly,
+      ]);
+    });
+
+    test('_handleRemove for account with email only', async () => {
+      const accountChip = chips.find(
+        chip => chip.account!.email === reviewerWithEmailOnly.email
+      );
+      accountChip!._handleRemoveTap(new MouseEvent('click'));
+      await flush();
+      assert.isTrue(removeReviewerStub.calledOnce);
+      assert.isTrue(removeReviewerStub.calledWith(reviewerWithEmailOnly.email));
+      assert.isTrue(reviewersChangedSpy.called);
+      expect(element.change!.reviewers.REVIEWER).to.have.deep.members([
+        reviewerWithId,
+        reviewerWithIdAndEmail,
+      ]);
+    });
+  });
+
+  test('tracking reviewers and ccs', () => {
+    let counter = 0;
+    function makeAccount() {
+      return {_account_id: counter++ as AccountId};
+    }
+
+    const owner = makeAccount();
+    const reviewer = makeAccount();
+    const cc = makeAccount();
+    const reviewers = {
+      REMOVED: [makeAccount()],
+      REVIEWER: [owner, reviewer],
+      CC: [owner, cc],
+    };
+
+    element.ccsOnly = false;
+    element.reviewersOnly = false;
+    element.change = {
+      ...createChange(),
+      owner,
+      reviewers,
+    };
+    assert.deepEqual(element._reviewers, [reviewer, cc]);
+
+    element.reviewersOnly = true;
+    element.change = {
+      ...createChange(),
+      owner,
+      reviewers,
+    };
+    assert.deepEqual(element._reviewers, [reviewer]);
+
+    element.ccsOnly = true;
+    element.reviewersOnly = false;
+    element.change = {
+      ...createChange(),
+      owner,
+      reviewers,
+    };
+    assert.deepEqual(element._reviewers, [cc]);
+  });
+
+  test('_handleAddTap passes mode with event', () => {
+    const fireStub = sinon.stub(element, 'dispatchEvent');
+    const e = {...new Event(''), preventDefault() {}};
+
+    element.ccsOnly = false;
+    element.reviewersOnly = false;
+    element._handleAddTap(e);
+    assert.equal(fireStub.lastCall.args[0].type, 'show-reply-dialog');
+    assert.deepEqual((fireStub.lastCall.args[0] as CustomEvent).detail, {
+      value: {
+        reviewersOnly: false,
+        ccsOnly: false,
+      },
+    });
+
+    element.reviewersOnly = true;
+    element._handleAddTap(e);
+    assert.equal(fireStub.lastCall.args[0].type, 'show-reply-dialog');
+    assert.deepEqual((fireStub.lastCall.args[0] as CustomEvent).detail, {
+      value: {reviewersOnly: true, ccsOnly: false},
+    });
+
+    element.ccsOnly = true;
+    element.reviewersOnly = false;
+    element._handleAddTap(e);
+    assert.equal(fireStub.lastCall.args[0].type, 'show-reply-dialog');
+    assert.deepEqual((fireStub.lastCall.args[0] as CustomEvent).detail, {
+      value: {ccsOnly: true, reviewersOnly: false},
+    });
+  });
+
+  test('dont show all reviewers button with 4 reviewers', () => {
+    const reviewers = [];
+    for (let i = 0; i < 4; i++) {
+      reviewers.push({
+        ...createAccountDetailWithId(i),
+        email: `${i}reviewer@google.com` as EmailAddress,
+        name: `reviewer${i}`,
+      });
+    }
+    element.ccsOnly = true;
+
+    element.change = {
+      ...createChange(),
+      owner: {
+        ...createAccountDetailWithId(111),
+      },
+      reviewers: {
+        CC: reviewers,
+      },
+    };
+    assert.equal(element._hiddenReviewerCount, 0);
+    assert.equal(element._displayedReviewers.length, 4);
+    assert.equal(element._reviewers.length, 4);
+    assert.isTrue(
+      (queryAndAssert(element, '.hiddenReviewers') as GrButton).hidden
+    );
+  });
+
+  test('account owner comes first in list of reviewers', () => {
+    const reviewers = [];
+    for (let i = 0; i < 4; i++) {
+      reviewers.push({
+        ...createAccountDetailWithId(i),
+        email: `${i}reviewer@google.com` as EmailAddress,
+        name: `reviewer${i}`,
+      });
+    }
+    element.reviewersOnly = true;
+    element.account = {
+      ...createAccountDetailWithId(1),
+    };
+    element.change = {
+      ...createChange(),
+      owner: {
+        ...createAccountDetailWithId(11),
+      },
+      reviewers: {
+        REVIEWER: reviewers,
+      },
+    };
+    flush();
+    assert.equal(element._displayedReviewers[0]._account_id, 1 as AccountId);
+  });
+
+  test('show all reviewers button with 9 reviewers', () => {
+    const reviewers = [];
+    for (let i = 0; i < 9; i++) {
+      reviewers.push({
+        ...createAccountDetailWithId(i),
+        email: `${i}reviewer@google.com` as EmailAddress,
+        name: `reviewer${i}`,
+      });
+    }
+    element.ccsOnly = true;
+
+    element.change = {
+      ...createChange(),
+      owner: {
+        ...createAccountDetailWithId(111),
+      },
+      reviewers: {
+        CC: reviewers,
+      },
+    };
+    assert.equal(element._hiddenReviewerCount, 3);
+    assert.equal(element._displayedReviewers.length, 6);
+    assert.equal(element._reviewers.length, 9);
+    assert.isFalse(
+      (queryAndAssert(element, '.hiddenReviewers') as GrButton).hidden
+    );
+  });
+
+  test('show all reviewers button', () => {
+    const reviewers = [];
+    for (let i = 0; i < 100; i++) {
+      reviewers.push({
+        ...createAccountDetailWithId(i),
+        email: `${i}reviewer@google.com` as EmailAddress,
+        name: `reviewer${i}`,
+      });
+    }
+    element.ccsOnly = true;
+
+    element.change = {
+      ...createChange(),
+      owner: {
+        ...createAccountDetailWithId(111),
+      },
+      reviewers: {
+        CC: reviewers,
+      },
+    };
+    assert.equal(element._hiddenReviewerCount, 94);
+    assert.equal(element._displayedReviewers.length, 6);
+    assert.equal(element._reviewers.length, 100);
+    assert.isFalse(
+      (queryAndAssert(element, '.hiddenReviewers') as GrButton).hidden
+    );
+
+    tap(queryAndAssert(element, '.hiddenReviewers'));
+
+    assert.equal(element._hiddenReviewerCount, 0);
+    assert.equal(element._displayedReviewers.length, 100);
+    assert.equal(element._reviewers.length, 100);
+    assert.isTrue(
+      (queryAndAssert(element, '.hiddenReviewers') as GrButton).hidden
+    );
+  });
+
+  test('votable labels', () => {
+    const change = {
+      ...createChange(),
+      labels: {
+        Foo: {
+          all: [
+            {
+              _account_id: 7 as AccountId,
+              permitted_voting_range: {max: 2, min: 0},
+            },
+          ],
+        },
+        Bar: {
+          all: [
+            {
+              ...createAccountDetailWithId(1),
+              permitted_voting_range: {max: 1, min: 0},
+            },
+            {
+              _account_id: 7 as AccountId,
+              permitted_voting_range: {max: 1, min: 0},
+            },
+          ],
+        },
+        FooBar: {
+          all: [{_account_id: 7 as AccountId, value: 0}],
+        },
+      },
+      permitted_labels: {
+        Foo: ['-1', ' 0', '+1', '+2'],
+        FooBar: ['-1', ' 0'],
+      },
+    };
+    assert.strictEqual(
+      element._computeVoteableText({...createAccountDetailWithId(1)}, change),
+      'Bar'
+    );
+    assert.strictEqual(
+      element._computeVoteableText({...createAccountDetailWithId(7)}, change),
+      'Foo: +2, Bar, FooBar'
+    );
+    assert.strictEqual(
+      element._computeVoteableText({...createAccountDetailWithId(2)}, change),
+      ''
+    );
+  });
+
+  test('fails gracefully when all is not included', () => {
+    const change = {
+      ...createChange(),
+      labels: {Foo: {}},
+      permitted_labels: {
+        Foo: ['-1', ' 0', '+1', '+2'],
+      },
+    };
+    assert.strictEqual(
+      element._computeVoteableText({...createAccountDetailWithId(1)}, change),
+      ''
+    );
+  });
+});
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-results.ts b/polygerrit-ui/app/elements/checks/gr-checks-results.ts
index 56aaf7b..da596fe 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-results.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-results.ts
@@ -15,6 +15,7 @@
  * limitations under the License.
  */
 import {html} from 'lit-html';
+import {classMap} from 'lit-html/directives/class-map';
 import {repeat} from 'lit-html/directives/repeat';
 import {
   css,
@@ -39,7 +40,6 @@
   allActions$,
   checksPatchsetNumber$,
   someProvidersAreLoading$,
-  checksWithMultipleAttempts$,
   RunResult,
   CheckRun,
 } from '../../services/checks/checks-model';
@@ -49,20 +49,23 @@
   hasCompletedWithoutResults,
   hasResultsOf,
   iconForCategory,
+  iconForLink,
+  tooltipForLink,
 } from '../../services/checks/checks-util';
 import {
   assertIsDefined,
   check,
   checkRequiredProperty,
 } from '../../utils/common-util';
-import {whenVisible} from '../../utils/dom-util';
+import {toggleClass, whenVisible} from '../../utils/dom-util';
 import {durationString} from '../../utils/date-util';
 import {charsOnly, pluralize} from '../../utils/string-util';
-import {fireRunSelectionReset} from './gr-checks-util';
+import {fireRunSelectionReset, isSelected} from './gr-checks-util';
 import {ChecksTabState} from '../../types/events';
-import {PatchSetNumber} from '../../types/common';
+import {ConfigInfo, PatchSetNumber} from '../../types/common';
 import {latestPatchNum$} from '../../services/change/change-model';
 import {appContext} from '../../services/app-context';
+import {repoConfig$} from '../../services/config/config-model';
 
 @customElement('gr-result-row')
 class GrResultRow extends GrLitElement {
@@ -76,9 +79,6 @@
   isExpandable = false;
 
   @property()
-  showAttempt = false;
-
-  @property()
   shouldRender = false;
 
   static get styles() {
@@ -97,9 +97,9 @@
         tr {
           border-top: 1px solid var(--border-color);
         }
-        iron-icon.launch {
+        iron-icon.link {
           color: var(--link-color);
-          margin-right: var(--spacing-s);
+          margin-right: var(--spacing-m);
         }
         td.iconCol {
           padding-left: var(--spacing-l);
@@ -114,7 +114,14 @@
           text-overflow: ellipsis;
         }
         .nameCol .attempt {
-          color: var(--deemphasized-text-color);
+          display: inline-block;
+          background-color: var(--tag-gray);
+          border-radius: var(--line-height-normal);
+          height: var(--line-height-normal);
+          width: var(--line-height-normal);
+          text-align: center;
+          vertical-align: top;
+          font-size: var(--font-size-small);
         }
         .summaryCol {
           /* Forces this column to get the remaining space that is left over by
@@ -130,7 +137,7 @@
         }
         td .summary-cell {
           display: flex;
-          max-width: calc(100vw - 700px);
+          max-width: calc(100vw - 630px);
         }
         td .summary-cell .summary {
           font-weight: var(--font-weight-bold);
@@ -148,8 +155,28 @@
           overflow: hidden;
           text-overflow: ellipsis;
         }
+        tr:hover {
+          background: var(--hover-background-color);
+        }
+        tr td .summary-cell .links,
+        tr td .summary-cell .actions,
+        tr.collapsed:hover td .summary-cell .links,
+        tr.collapsed:hover td .summary-cell .actions,
+        :host(.dropdown-open) tr td .summary-cell .links,
+        :host(.dropdown-open) tr td .summary-cell .actions {
+          display: inline-block;
+          margin-left: var(--spacing-s);
+        }
+        tr.collapsed td .summary-cell .links,
+        tr.collapsed td .summary-cell .actions {
+          display: none;
+        }
+        tr.collapsed:hover .summary-cell .tags,
+        tr.collapsed:hover .summary-cell .label {
+          display: none;
+        }
         td .summary-cell .tags .tag {
-          color: var(--deemphasized-text-color);
+          color: var(--primary-text-color);
           display: inline-block;
           border-radius: 20px;
           background-color: var(--tag-background);
@@ -157,7 +184,7 @@
           margin-left: var(--spacing-s);
         }
         td .summary-cell .label {
-          color: var(--deemphasized-text-color);
+          color: var(--primary-text-color);
           display: inline-block;
           border-radius: 20px;
           background-color: var(--label-background);
@@ -182,6 +209,18 @@
         .tag.brown {
           background-color: var(--tag-brown);
         }
+        .actions gr-checks-action,
+        .actions gr-dropdown {
+          /* Fitting a 28px button into 20px line-height. */
+          margin: -4px 0;
+          vertical-align: top;
+        }
+        #moreActions iron-icon {
+          color: var(--link-color);
+        }
+        #moreMessage {
+          display: none;
+        }
       `,
     ];
   }
@@ -214,21 +253,24 @@
       `;
     }
     return html`
-      <tr class="container" @click="${this.toggleExpanded}">
+      <tr
+        class="${classMap({container: true, collapsed: !this.isExpanded})}"
+        @click="${this.toggleExpanded}"
+      >
         <td class="iconCol">
           <div>${this.renderIcon()}</div>
         </td>
         <td class="nameCol">
           <div>
             <span>${this.result.checkName}</span>
-            <span class="attempt" ?hidden="${!this.showAttempt}"
-              >[${this.result.attempt}]</span
+            <span class="attempt" ?hidden="${this.result.isSingleAttempt}"
+              >${this.result.attempt}</span
             >
           </div>
         </td>
         <td class="summaryCol">
           <div class="summary-cell">
-            ${(this.result.links?.slice(0, 5) ?? []).map(this.renderLink)}
+            ${(this.result.links?.slice(0, 1) ?? []).map(this.renderLink)}
             ${this.renderSummary(this.result.summary)}
             <div class="message">
               ${this.isExpanded ? '' : this.result.message}
@@ -236,7 +278,7 @@
             <div class="tags">
               ${(this.result.tags ?? []).map(t => this.renderTag(t))}
             </div>
-            ${this.renderLabel()}
+            ${this.renderLabel()} ${this.renderLinks()} ${this.renderActions()}
           </div>
           ${this.renderExpanded()}
         </td>
@@ -289,20 +331,6 @@
     `;
   }
 
-  renderLink(link: Link) {
-    const tooltipText = link.tooltip ?? 'Link to details';
-    return html`
-      <a href="${link.url}" target="_blank">
-        <iron-icon
-          aria-label="external link to details"
-          class="launch"
-          icon="gr-icons:launch"
-        ></iron-icon>
-        <paper-tooltip offset="5">${tooltipText}</paper-tooltip>
-      </a>
-    `;
-  }
-
   renderIcon() {
     if (this.result?.status !== RunStatus.RUNNING) return;
     return html`<iron-icon icon="gr-icons:timelapse"></iron-icon>`;
@@ -314,6 +342,77 @@
     return html`<div class="label">${label}</div>`;
   }
 
+  renderLinks() {
+    const links = (this.result?.links ?? []).slice(1);
+    if (links.length === 0) return;
+    return html`<div class="links">${links.map(this.renderLink)}</div>`;
+  }
+
+  renderLink(link: Link) {
+    const tooltipText = link.tooltip ?? tooltipForLink(link.icon);
+    return html`<a href="${link.url}" target="_blank"
+      ><iron-icon
+        aria-label="external link to details"
+        class="link"
+        icon="gr-icons:${iconForLink(link.icon)}"
+      ></iron-icon
+      ><paper-tooltip offset="5">${tooltipText}</paper-tooltip></a
+    >`;
+  }
+
+  private renderActions() {
+    const actions = this.result?.actions ?? [];
+    if (actions.length === 0) return;
+    const overflowItems = actions.slice(2).map(action => {
+      return {...action, id: action.name};
+    });
+    return html`<div class="actions">
+      ${this.renderAction(actions[0])} ${this.renderAction(actions[1])}
+      <gr-dropdown
+        id="moreActions"
+        link=""
+        vertical-offset="32"
+        horizontal-align="right"
+        @tap-item="${this.handleAction}"
+        @opened-changed="${(e: CustomEvent) =>
+          toggleClass(this, 'dropdown-open', e.detail.value)}"
+        ?hidden="${overflowItems.length === 0}"
+        .items="${overflowItems}"
+      >
+        <iron-icon icon="gr-icons:more-vert" aria-labelledby="moreMessage">
+        </iron-icon>
+        <span id="moreMessage">More</span>
+      </gr-dropdown>
+    </div>`;
+  }
+
+  private handleAction(e: CustomEvent<Action>) {
+    fireActionTriggered(this, e.detail);
+  }
+
+  private renderAction(action?: Action) {
+    if (!action) return;
+    return html`<gr-checks-action .action="${action}"></gr-checks-action>`;
+  }
+
+  renderPrimaryActions() {
+    const primaryActions = (this.result?.actions ?? []).slice(0, 2);
+    if (primaryActions.length === 0) return;
+    return html`
+      <div class="primaryActions">${primaryActions.map(this.renderAction)}</div>
+    `;
+  }
+
+  renderSecondaryActions() {
+    const secondaryActions = (this.result?.actions ?? []).slice(2);
+    if (secondaryActions.length === 0) return;
+    return html`
+      <div class="secondaryActions">
+        ${secondaryActions.map(this.renderAction)}
+      </div>
+    `;
+  }
+
   renderTag(tag: Tag) {
     return html`<div class="tag ${tag.color}">${tag.name}</div>`;
   }
@@ -324,18 +423,25 @@
   @property()
   result?: RunResult;
 
+  @property()
+  repoConfig?: ConfigInfo;
+
   static get styles() {
     return [
       sharedStyles,
       css`
         .message {
           padding: var(--spacing-m) var(--spacing-m) var(--spacing-m) 0;
-          white-space: pre-wrap;
         }
       `,
     ];
   }
 
+  constructor() {
+    super();
+    this.subscribe('repoConfig', repoConfig$);
+  }
+
   render() {
     if (!this.result) return '';
     return html`
@@ -348,9 +454,12 @@
           name="result"
           .value="${this.result}"
         ></gr-endpoint-param>
-        <div class="message">
-          ${this.result.message}
-        </div>
+        <gr-formatted-text
+          no-trailing-margin=""
+          class="message"
+          content="${this.result.message}"
+          config="${this.repoConfig}"
+        ></gr-formatted-text>
       </gr-endpoint-decorator>
     `;
   }
@@ -364,9 +473,6 @@
   @internalProperty()
   filterRegExp = new RegExp('');
 
-  @internalProperty()
-  checksWithMultipleAttempts: string[] = [];
-
   @property()
   runs: CheckRun[] = [];
 
@@ -393,6 +499,13 @@
   @property()
   selectedRunsCount = 0;
 
+  /** Maps checkName to selected attempt number. `undefined` means `latest`. */
+  @property()
+  selectedAttempts: Map<string, number | undefined> = new Map<
+    string,
+    number | undefined
+  >();
+
   /**
    * This is the current state of whether a section is expanded or not. As long
    * as isSectionExpandedByUser is false this will be computed by a default rule
@@ -415,7 +528,6 @@
     this.subscribe('checksPatchsetNumber', checksPatchsetNumber$);
     this.subscribe('latestPatchsetNumber', latestPatchNum$);
     this.subscribe('someProvidersAreLoading', someProvidersAreLoading$);
-    this.subscribe('checksWithMultipleAttempts', checksWithMultipleAttempts$);
   }
 
   static get styles() {
@@ -592,12 +704,8 @@
           </div>
         </div>
         <div class="headerBottomRow">
-          <div class="left">
-            ${this.renderFilter()}
-          </div>
-          <div class="right">
-            ${this.renderActions()}
-          </div>
+          <div class="left">${this.renderFilter()}</div>
+          <div class="right">${this.renderActions()}</div>
         </div>
       </div>
       <div class="body">
@@ -637,9 +745,7 @@
 
   private renderAction(action?: Action) {
     if (!action) return;
-    return html`<gr-checks-top-level-action
-      .action="${action}"
-    ></gr-checks-top-level-action>`;
+    return html`<gr-checks-action .action="${action}"></gr-checks-action>`;
   }
 
   private onPatchsetSelected(e: CustomEvent<{value: string}>) {
@@ -662,7 +768,10 @@
   }
 
   renderFilter() {
-    if (this.selectedRunsCount === 0 && allResults(this.runs).length <= 3) {
+    const runs = this.runs.filter(run =>
+      isSelected(this.selectedAttempts, run)
+    );
+    if (this.selectedRunsCount === 0 && allResults(runs).length <= 3) {
       if (this.filterRegExp.source.length > 0) {
         this.filterRegExp = new RegExp('');
       }
@@ -676,9 +785,7 @@
           placeholder="Filter results by regular expression"
           @input="${this.onInput}"
         />
-        <div class="selection">
-          ${this.renderSelectionFilter()}
-        </div>
+        <div class="selection">${this.renderSelectionFilter()}</div>
       </div>
     `;
   }
@@ -707,15 +814,19 @@
 
   renderSection(category: Category | 'SUCCESS') {
     const catString = category.toString().toLowerCase();
-    let runs = this.runs;
+    let runs = this.runs.filter(run => isSelected(this.selectedAttempts, run));
     if (category === 'SUCCESS') {
       runs = runs.filter(hasCompletedWithoutResults);
     } else {
       runs = runs.filter(r => hasResultsOf(r, category));
     }
-    const all = runs.reduce((allResults: RunResult[], run) => {
-      return [...allResults, ...this.computeRunResults(category, run)];
-    }, []);
+    const all = runs.reduce(
+      (allResults: RunResult[], run) => [
+        ...allResults,
+        ...this.computeRunResults(category, run),
+      ],
+      []
+    );
     const filtered = all.filter(
       result =>
         this.filterRegExp.test(result.checkName) ||
@@ -775,14 +886,11 @@
         <tbody>
           ${repeat(
             filtered,
-            result => result.externalId,
+            result => result.internalResultId,
             result => html`
               <gr-result-row
                 class="${charsOnly(result.checkName)}"
                 .result="${result}"
-                .showAttempt="${this.checksWithMultipleAttempts.includes(
-                  result.checkName
-                )}"
               ></gr-result-row>
             `
           )}
@@ -823,6 +931,7 @@
 
   computeSuccessfulRunResult(run: CheckRun): RunResult {
     const adaptedRun: RunResult = {
+      internalResultId: run.internalRunId + '-0',
       category: Category.INFO, // will not be used, but is required
       summary: run.statusDescription ?? '',
       ...run,
@@ -849,8 +958,8 @@
   }
 }
 
-@customElement('gr-checks-top-level-action')
-export class GrChecksTopLevelAction extends GrLitElement {
+@customElement('gr-checks-action')
+export class GrChecksAction extends GrLitElement {
   @property()
   action!: Action;
 
@@ -862,6 +971,9 @@
   static get styles() {
     return [
       css`
+        :host {
+          display: inline-block;
+        }
         gr-button {
           --padding: var(--spacing-s) var(--spacing-m);
         }
@@ -893,6 +1005,6 @@
     'gr-result-row': GrResultRow;
     'gr-result-expanded': GrResultExpanded;
     'gr-checks-results': GrChecksResults;
-    'gr-checks-top-level-action': GrChecksTopLevelAction;
+    'gr-checks-action': GrChecksAction;
   }
 }
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-runs.ts b/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
index 62e933d..dc09479 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
@@ -29,6 +29,7 @@
 import {Action, RunStatus} from '../../api/checks';
 import {sharedStyles} from '../../styles/shared-styles';
 import {
+  AttemptDetail,
   compareByWorstCategory,
   fireActionTriggered,
   iconForCategory,
@@ -44,14 +45,17 @@
   fakeRun1,
   fakeRun2,
   fakeRun3,
-  fakeRun4,
+  fakeRun4_1,
+  fakeRun4_2,
+  fakeRun4_3,
+  fakeRun4_4,
   updateStateSetResults,
-  checksWithMultipleAttempts$,
 } from '../../services/checks/checks-model';
 import {assertIsDefined} from '../../utils/common-util';
 import {whenVisible} from '../../utils/dom-util';
-import {fireRunSelected} from './gr-checks-util';
+import {fireAttemptSelected, fireRunSelected} from './gr-checks-util';
 import {ChecksTabState} from '../../types/events';
+import {charsOnly} from '../../utils/string-util';
 
 @customElement('gr-checks-run')
 export class GrChecksRun extends GrLitElement {
@@ -81,7 +85,14 @@
           font-weight: var(--font-weight-bold);
         }
         .attempt {
-          color: var(--deemphasized-text-color);
+          display: inline-block;
+          background-color: var(--tag-gray);
+          border-radius: var(--line-height-normal);
+          height: var(--line-height-normal);
+          width: var(--line-height-normal);
+          text-align: center;
+          vertical-align: top;
+          font-size: var(--font-size-small);
         }
         .chip.error {
           border-left: var(--thick-border) solid var(--error-foreground);
@@ -138,6 +149,23 @@
              that would not have been a nice click target. */
           margin: calc(0px - var(--spacing-xs));
         }
+        .attemptDetails {
+          padding-bottom: var(--spacing-s);
+        }
+        .attemptDetail {
+          /* This is thick-border (6) + spacing-m (8) + icon (20) + padding. */
+          padding-left: 39px;
+          padding-top: var(--spacing-s);
+        }
+        .attemptDetail input {
+          width: 14px;
+          height: 14px;
+          /* The next 3 are for placing in the middle of 20px line-height. */
+          vertical-align: top;
+          position: relative;
+          top: 3px;
+          margin-right: var(--spacing-s);
+        }
       `,
     ];
   }
@@ -152,10 +180,10 @@
   selected = false;
 
   @property()
-  deselected = false;
+  selectedAttempt?: number;
 
   @property()
-  showAttempt = false;
+  deselected = false;
 
   @property()
   shouldRender = false;
@@ -169,6 +197,21 @@
     );
   }
 
+  protected updated(changedProperties: PropertyValues) {
+    super.updated(changedProperties);
+
+    // For some reason the browser does not pick up the correct `checked` state
+    // that is set in renderAttempt(). So we have to set it programmatically
+    // here.
+    const selectedAttempt = this.selectedAttempt ?? this.run.attempt;
+    const inputToBeSelected = this.shadowRoot?.querySelector(
+      `.attemptDetails input#attempt-${selectedAttempt}`
+    ) as HTMLInputElement | undefined;
+    if (inputToBeSelected) {
+      inputToBeSelected.checked = true;
+    }
+  }
+
   render() {
     if (!this.shouldRender) return html`<div class="chip">Loading ...</div>`;
 
@@ -189,8 +232,8 @@
           <iron-icon class="${icon}" icon="gr-icons:${icon}"></iron-icon>
           ${this.renderAdditionalIcon()}
           <span class="name">${this.run.checkName}</span>
-          <span class="attempt" ?hidden="${!this.showAttempt}"
-            >[${this.run.attempt}]</span
+          <span class="attempt" ?hidden="${this.run.isSingleAttempt}"
+            >${this.run.attempt}</span
           >
         </div>
         <div class="right">
@@ -204,9 +247,45 @@
             : ''}
         </div>
       </div>
+      <div
+        class="attemptDetails"
+        ?hidden="${this.run.isSingleAttempt || !this.selected}"
+      >
+        ${this.run.attemptDetails.map(a => this.renderAttempt(a))}
+      </div>
     `;
   }
 
+  isSelected(detail: AttemptDetail) {
+    // this.selectedAttempt may be undefined, then choose the latest attempt,
+    // which is what this.run has.
+    const selectedAttempt = this.selectedAttempt ?? this.run.attempt;
+    return detail.attempt === selectedAttempt;
+  }
+
+  renderAttempt(detail: AttemptDetail) {
+    const checkNameId = charsOnly(this.run.checkName).toLowerCase();
+    const id = `attempt-${detail.attempt}`;
+    const icon = detail.icon;
+    return html`<div class="attemptDetail">
+      <input
+        type="radio"
+        id="${id}"
+        name="${`${checkNameId}-attempt-choice`}"
+        ?checked="${this.isSelected(detail)}"
+        @change="${() => this.handleAttemptChange(detail)}"
+      />
+      <iron-icon class="${icon}" icon="gr-icons:${icon}"></iron-icon>
+      <label for="${id}">Attempt ${detail.attempt}</label>
+    </div>`;
+  }
+
+  handleAttemptChange(detail: AttemptDetail) {
+    if (!this.isSelected(detail)) {
+      fireAttemptSelected(this, this.run.checkName, detail.attempt);
+    }
+  }
+
   renderFilterIcon() {
     if (!this.selected) return;
     return html`
@@ -255,8 +334,12 @@
   @property()
   selectedRuns: string[] = [];
 
-  @internalProperty()
-  checksWithMultipleAttempts: string[] = [];
+  /** Maps checkName to selected attempt number. `undefined` means `latest`. */
+  @property()
+  selectedAttempts: Map<string, number | undefined> = new Map<
+    string,
+    number | undefined
+  >();
 
   @property()
   tabState?: ChecksTabState;
@@ -266,7 +349,6 @@
   constructor() {
     super();
     this.subscribe('runs', allRuns$);
-    this.subscribe('checksWithMultipleAttempts', checksWithMultipleAttempts$);
   }
 
   static get styles() {
@@ -354,19 +436,23 @@
         <gr-button link @click="${this.none}">none</gr-button>
         <gr-button
           link
-          @click="${() => this.toggle('f0', fakeRun0, fakeActions)}"
+          @click="${() => this.toggle('f0', [fakeRun0], fakeActions)}"
           >0</gr-button
         >
-        <gr-button link @click="${() => this.toggle('f1', fakeRun1)}"
+        <gr-button link @click="${() => this.toggle('f1', [fakeRun1])}"
           >1</gr-button
         >
-        <gr-button link @click="${() => this.toggle('f2', fakeRun2)}"
+        <gr-button link @click="${() => this.toggle('f2', [fakeRun2])}"
           >2</gr-button
         >
-        <gr-button link @click="${() => this.toggle('f3', fakeRun3)}"
+        <gr-button link @click="${() => this.toggle('f3', [fakeRun3])}"
           >3</gr-button
         >
-        <gr-button link @click="${() => this.toggle('f4', fakeRun4)}"
+        <gr-button
+          link
+          @click="${() => {
+            this.toggle('f4', [fakeRun4_1, fakeRun4_2, fakeRun4_3, fakeRun4_4]);
+          }}"
           >4</gr-button
         >
         <gr-button link @click="${this.all}">all</gr-button>
@@ -392,16 +478,22 @@
     updateStateSetResults('f1', [fakeRun1]);
     updateStateSetResults('f2', [fakeRun2]);
     updateStateSetResults('f3', [fakeRun3]);
-    updateStateSetResults('f4', [fakeRun4]);
+    updateStateSetResults('f4', [
+      fakeRun4_1,
+      fakeRun4_2,
+      fakeRun4_3,
+      fakeRun4_4,
+    ]);
   }
 
-  toggle(plugin: string, run: CheckRun, actions: Action[] = []) {
-    const newRuns = this.runs.includes(run) ? [] : [run];
+  toggle(plugin: string, runs: CheckRun[], actions: Action[] = []) {
+    const newRuns = this.runs.includes(runs[0]) ? [] : runs;
     updateStateSetResults(plugin, newRuns, actions);
   }
 
   renderSection(status: RunStatus) {
     const runs = this.runs
+      .filter(r => r.isLatestAttempt)
       .filter(r => r.status === status)
       .filter(r => this.filterRegExp.test(r.checkName))
       .sort(compareByWorstCategory);
@@ -418,9 +510,7 @@
           <iron-icon class="expandIcon" icon="${icon}"></iron-icon>
           <h3 class="heading-3">${status.toLowerCase()}</h3>
         </div>
-        <div class="sectionRuns">
-          ${runs.map(run => this.renderRun(run))}
-        </div>
+        <div class="sectionRuns">${runs.map(run => this.renderRun(run))}</div>
       </div>
     `;
   }
@@ -432,13 +522,14 @@
   }
 
   renderRun(run: CheckRun) {
-    const selected = this.selectedRuns.includes(run.checkName);
-    const deselected = !selected && this.selectedRuns.length > 0;
+    const selectedRun = this.selectedRuns.includes(run.checkName);
+    const selectedAttempt = this.selectedAttempts.get(run.checkName);
+    const deselected = !selectedRun && this.selectedRuns.length > 0;
     return html`<gr-checks-run
       .run="${run}"
-      .selected="${selected}"
+      .selected="${selectedRun}"
+      .selectedAttempt="${selectedAttempt}"
       .deselected="${deselected}"
-      .showAttempt="${this.checksWithMultipleAttempts.includes(run.checkName)}"
     ></gr-checks-run>`;
   }
 
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-tab.ts b/polygerrit-ui/app/elements/checks/gr-checks-tab.ts
index d017eb7..beec4c8 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-tab.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-tab.ts
@@ -36,7 +36,7 @@
 import {changeNum$} from '../../services/change/change-model';
 import {NumericChangeId, PatchSetNumber} from '../../types/common';
 import {ActionTriggeredEvent} from '../../services/checks/checks-util';
-import {RunSelectedEvent} from './gr-checks-util';
+import {AttemptSelectedEvent, RunSelectedEvent} from './gr-checks-util';
 import {ChecksTabState} from '../../types/events';
 import {fireAlert} from '../../utils/event-util';
 import {appContext} from '../../services/app-context';
@@ -67,6 +67,13 @@
   @internalProperty()
   selectedRuns: string[] = [];
 
+  /** Maps checkName to selected attempt number. `undefined` means `latest`. */
+  @internalProperty()
+  selectedAttempts: Map<string, number | undefined> = new Map<
+    string,
+    number | undefined
+  >();
+
   private readonly checksService = appContext.checksService;
 
   constructor() {
@@ -112,14 +119,17 @@
           class="runs"
           .runs="${this.runs}"
           .selectedRuns="${this.selectedRuns}"
+          .selectedAttempts="${this.selectedAttempts}"
           .tabState="${this.tabState}"
           @run-selected="${this.handleRunSelected}"
+          @attempt-selected="${this.handleAttemptSelected}"
         ></gr-checks-runs>
         <gr-checks-results
           class="results"
           .tabState="${this.tabState}"
           .runs="${filteredRuns}"
           .selectedRunsCount="${this.selectedRuns.length}"
+          .selectedAttempts="${this.selectedAttempts}"
           @run-selected="${this.handleRunSelected}"
         ></gr-checks-results>
       </div>
@@ -170,6 +180,7 @@
   handleRunSelected(e: RunSelectedEvent) {
     if (e.detail.reset) {
       this.selectedRuns = [];
+      this.selectedAttempts = new Map();
       return;
     }
     if (e.detail.checkName) {
@@ -177,9 +188,18 @@
     }
   }
 
+  handleAttemptSelected(e: AttemptSelectedEvent) {
+    const {checkName, attempt} = e.detail;
+    this.selectedAttempts.set(checkName, attempt);
+    // Force property update.
+    this.selectedAttempts = new Map(this.selectedAttempts);
+  }
+
   toggleSelected(checkName: string) {
     if (this.selectedRuns.includes(checkName)) {
       this.selectedRuns = this.selectedRuns.filter(r => r !== checkName);
+      this.selectedAttempts.set(checkName, undefined);
+      this.selectedAttempts = new Map(this.selectedAttempts);
     } else {
       this.selectedRuns = [...this.selectedRuns, checkName];
     }
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-util.ts b/polygerrit-ui/app/elements/checks/gr-checks-util.ts
index 4d8d8cb..9a68e5b 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-util.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-util.ts
@@ -14,6 +14,34 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+import {CheckRun} from '../../services/checks/checks-model';
+
+export interface AttemptSelectedEventDetail {
+  checkName: string;
+  attempt: number | undefined;
+}
+
+export type AttemptSelectedEvent = CustomEvent<AttemptSelectedEventDetail>;
+
+declare global {
+  interface HTMLElementEventMap {
+    'attempt-selected': AttemptSelectedEvent;
+  }
+}
+
+export function fireAttemptSelected(
+  target: EventTarget,
+  checkName: string,
+  attempt: number | undefined
+) {
+  target.dispatchEvent(
+    new CustomEvent('attempt-selected', {
+      detail: {checkName, attempt},
+      composed: true,
+      bubbles: true,
+    })
+  );
+}
 
 export interface RunSelectedEventDetail {
   reset: boolean;
@@ -47,3 +75,13 @@
     })
   );
 }
+
+export function isSelected(
+  selectedAttempts: Map<string, number | undefined>,
+  run: CheckRun
+) {
+  const selected = selectedAttempts.get(run.checkName);
+  return (
+    (selected === undefined && run.isLatestAttempt) || selected === run.attempt
+  );
+}
diff --git a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.js b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.js
index 7d643a0..91f119e 100644
--- a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.js
+++ b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.js
@@ -21,6 +21,7 @@
 import {__testOnly_ErrorType} from './gr-error-manager.js';
 import {stubRestApi} from '../../../test/test-utils.js';
 import {appContext} from '../../../services/app-context.js';
+import {createPreferences} from '../../../test/test-data-generators.js';
 
 const basicFixture = fixtureFromElement('gr-error-manager');
 
@@ -40,6 +41,8 @@
           .returns(Promise.resolve({ok: true, status: 204}));
       getLoggedInStub = stubRestApi('getLoggedIn')
           .callsFake(() => appContext.authService.authCheck());
+      stubRestApi('getPreferences').returns(Promise.resolve(
+          createPreferences()));
       element = basicFixture.instantiate();
       element._authService.clearCache();
       toastSpy = sinon.spy(element, '_createToastAlert');
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts
index a674a8a..816ed87 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts
@@ -239,7 +239,7 @@
       } else if (items.length > 0) {
         links.push({
           title: m.name,
-          links: topMenuLinks[m.name] = items,
+          links: (topMenuLinks[m.name] = items),
         });
       }
     }
diff --git a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts
index 9c63f8b..a3ddff3 100644
--- a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts
+++ b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts
@@ -34,6 +34,7 @@
 import {CustomKeyboardEvent} from '../../../types/events';
 import {MergeabilityComputationBehavior} from '../../../constants/constants';
 import {appContext} from '../../../services/app-context';
+import {getKeyboardEvent} from '../../../utils/dom-util';
 
 // Possible static search options for auto complete, without negations.
 const SEARCH_OPERATORS: ReadonlyArray<string> = [
@@ -385,7 +386,7 @@
   }
 
   _handleSearch(e: CustomKeyboardEvent) {
-    const keyboardEvent = this.getKeyboardEvent(e);
+    const keyboardEvent = getKeyboardEvent(e);
     if (
       this.shouldSuppressKeyboardShortcut(e) ||
       (this.modifierPressed(e) && !keyboardEvent.shiftKey)
diff --git a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.ts b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.ts
index fa8e69d..b382495 100644
--- a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.ts
+++ b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.ts
@@ -146,12 +146,8 @@
     const commentMap: CommentMap = {};
     for (const response of responses) {
       for (const [path, comments] of Object.entries(response)) {
-        if (
-          comments.some(c => {
-            // If don't care about patch range, we know that the path exists.
-            return !patchRange || isInPatchRange(c, patchRange);
-          })
-        ) {
+        // If don't care about patch range, we know that the path exists.
+        if (comments.some(c => !patchRange || isInPatchRange(c, patchRange))) {
           commentMap[path] = true;
         }
       }
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element.ts b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element.ts
index d12fa92..96206f2 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element.ts
@@ -46,8 +46,9 @@
 import {GrDiffLine, LineNumber} from '../gr-diff/gr-diff-line';
 import {GrDiffGroup} from '../gr-diff/gr-diff-group';
 import {PolymerSpliceChange} from '@polymer/polymer/interfaces';
-import {getLineNumber} from '../gr-diff/gr-diff-utils';
+import {getLineNumber, getSideByLineEl} from '../gr-diff/gr-diff-utils';
 import {fireAlert, fireEvent} from '../../../utils/event-util';
+import {TokenHighlightLayer} from './token-highlight-layer';
 
 const TRAILING_WHITESPACE_PATTERN = /\s+$/;
 
@@ -249,6 +250,7 @@
       this.$.rangeLayer,
       this.$.coverageLayerLeft,
       this.$.coverageLayerRight,
+      new TokenHighlightLayer(),
     ];
 
     if (this.layers) {
@@ -257,26 +259,6 @@
     this._layers = layers;
   }
 
-  getLineElByChild(node?: Node): HTMLElement | null {
-    while (node) {
-      if (node instanceof Element) {
-        if (node.classList.contains('lineNum')) {
-          return node as HTMLElement;
-        }
-        if (node.classList.contains('section')) {
-          return null;
-        }
-      }
-      node = node.previousSibling ?? node.parentElement ?? undefined;
-    }
-    return null;
-  }
-
-  getLineNumberByChild(node: Node) {
-    const lineEl = this.getLineElByChild(node);
-    return getLineNumber(lineEl);
-  }
-
   getContentTdByLine(lineNumber: LineNumber, side?: Side, root?: Element) {
     if (!this._builder) return null;
     return this._builder.getContentTdByLine(lineNumber, side, root);
@@ -293,7 +275,7 @@
     if (!lineEl) return null;
     const line = getLineNumber(lineEl);
     if (!line) return null;
-    const side = this.getSideByLineEl(lineEl);
+    const side = getSideByLineEl(lineEl);
     // Performance optimization because we already have an element in the
     // correct row
     const row = this._getDiffRowByChild(lineEl);
@@ -307,10 +289,6 @@
     );
   }
 
-  getSideByLineEl(lineEl: Element) {
-    return lineEl.classList.contains(Side.RIGHT) ? Side.RIGHT : Side.LEFT;
-  }
-
   emitGroup(group: GrDiffGroup, sectionEl: HTMLElement) {
     if (!this._builder) return;
     this._builder.emitGroup(group, sectionEl);
@@ -515,9 +493,7 @@
   }
 
   _createTrailingWhitespaceLayer(): DiffLayer {
-    const show = () => {
-      return this._showTrailingWhitespace;
-    };
+    const show = () => this._showTrailingWhitespace;
 
     return {
       annotate(contentEl: HTMLElement, _: HTMLElement, line: GrDiffLine) {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified.ts b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified.ts
index e927fdf..2067455 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified.ts
@@ -122,7 +122,14 @@
       Side.RIGHT
     );
     row.appendChild(lineNumberEl);
-    row.appendChild(this._createTextEl(lineNumberEl, line));
+    let side = undefined;
+    if (line.type === GrDiffLineType.ADD || line.type === GrDiffLineType.BOTH) {
+      side = Side.RIGHT;
+    }
+    if (line.type === GrDiffLineType.REMOVE) {
+      side = Side.LEFT;
+    }
+    row.appendChild(this._createTextEl(lineNumberEl, line, side));
     return row;
   }
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.ts b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.ts
index 874f572..65c991c 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.ts
@@ -16,6 +16,8 @@
  */
 import {
   ContentLoadNeededEventDetail,
+  ContextButtonType,
+  DiffContextExpandedExternalDetail,
   MovedLinkClickedEventDetail,
   RenderPreferences,
 } from '../../../api/diff';
@@ -57,13 +59,8 @@
 
 const PARTIAL_CONTEXT_AMOUNT = 10;
 
-enum ContextButtonType {
-  ABOVE = 'above',
-  BELOW = 'below',
-  ALL = 'all',
-}
-
-export interface DiffContextExpandedEventDetail {
+export interface DiffContextExpandedEventDetail
+  extends DiffContextExpandedExternalDetail {
   groups: GrDiffGroup[];
   section: HTMLElement;
   numLines: number;
@@ -158,13 +155,6 @@
     REMOVED: 'edit_a',
   };
 
-  // TODO(TS): Replace usages with ContextButtonType enum.
-  static readonly ContextButtonType = {
-    ABOVE: 'above',
-    BELOW: 'below',
-    ALL: 'all',
-  };
-
   abstract addColumns(outputEl: HTMLElement, fontSize: number): void;
 
   abstract buildSectionElement(group: GrDiffGroup): HTMLElement;
@@ -455,7 +445,8 @@
     contextGroups: GrDiffGroup[],
     numLines: number
   ) {
-    const context = PARTIAL_CONTEXT_AMOUNT;
+    const linesToExpand =
+      type === ContextButtonType.ALL ? numLines : PARTIAL_CONTEXT_AMOUNT;
     const button = this._createElement('gr-button', 'showContext');
     button.classList.add('contextControlButton');
     button.setAttribute('link', 'true');
@@ -464,11 +455,11 @@
     let text = '';
     let groups: GrDiffGroup[] = []; // The groups that replace this one if tapped.
     let requiresLoad = false;
-    if (type === GrDiffBuilder.ContextButtonType.ALL) {
-      text = `+${pluralize(numLines, 'common line')}`;
+    if (type === ContextButtonType.ALL) {
+      text = `+${pluralize(linesToExpand, 'common line')}`;
       button.setAttribute(
         'aria-label',
-        `Show ${pluralize(numLines, 'common line')}`
+        `Show ${pluralize(linesToExpand, 'common line')}`
       );
       requiresLoad = contextGroups.find(c => !!c.skip) !== undefined;
       if (requiresLoad) {
@@ -476,21 +467,21 @@
         text += ' (too large)';
       }
       groups.push(...contextGroups);
-    } else if (type === GrDiffBuilder.ContextButtonType.ABOVE) {
-      groups = hideInContextControl(contextGroups, context, numLines);
-      text = `+${context}`;
+    } else if (type === ContextButtonType.ABOVE) {
+      groups = hideInContextControl(contextGroups, linesToExpand, numLines);
+      text = `+${linesToExpand}`;
       button.classList.add('aboveButton');
       button.setAttribute(
         'aria-label',
-        `Show ${pluralize(context, 'line')} above`
+        `Show ${pluralize(linesToExpand, 'line')} above`
       );
-    } else if (type === GrDiffBuilder.ContextButtonType.BELOW) {
-      groups = hideInContextControl(contextGroups, 0, numLines - context);
-      text = `+${context}`;
+    } else if (type === ContextButtonType.BELOW) {
+      groups = hideInContextControl(contextGroups, 0, numLines - linesToExpand);
+      text = `+${linesToExpand}`;
       button.classList.add('belowButton');
       button.setAttribute(
         'aria-label',
-        `Show ${pluralize(context, 'line')} below`
+        `Show ${pluralize(linesToExpand, 'line')} below`
       );
     }
     const textSpan = this._createElement('span', 'showContext');
@@ -523,6 +514,8 @@
           groups,
           section,
           numLines,
+          buttonType: type,
+          expandedLines: linesToExpand,
         });
       });
     }
@@ -612,14 +605,14 @@
         contentText.setAttribute('data-side', side);
       }
 
-      if (lineNumberEl) {
+      if (lineNumberEl && side) {
         for (const layer of this.layers) {
           if (typeof layer.annotate === 'function') {
-            layer.annotate(contentText, lineNumberEl, line);
+            layer.annotate(contentText, lineNumberEl, line, side);
           }
         }
       } else {
-        console.error('The lineNumberEl is null, skipping layer annotations.');
+        console.error('lineNumberEl or side not set, skipping layer.annotate');
       }
 
       td.appendChild(contentText);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer.ts b/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer.ts
new file mode 100644
index 0000000..d0b3d3c
--- /dev/null
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer.ts
@@ -0,0 +1,259 @@
+/**
+ * @license
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import {DiffLayer, DiffLayerListener} from '../../../types/types';
+import {GrDiffLine, Side} from '../../../api/diff';
+import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
+import {debounce, DelayedTask} from '../../../utils/async-util';
+import {
+  getLineNumberByChild,
+  lineNumberToNumber,
+} from '../gr-diff/gr-diff-utils';
+import {appContext} from '../../../services/app-context';
+import {KnownExperimentId} from '../../../services/flags/flags';
+
+const tokenMatcher = new RegExp(/[a-zA-Z0-9_-]+/g);
+
+/** CSS class for all tokens. */
+const CSS_TOKEN = 'token';
+
+/** CSS class for the currently hovered token. */
+const CSS_HIGHLIGHT = 'token-highlight';
+
+const UPDATE_TOKEN_TASK_DELAY_MS = 50;
+
+const LINE_LENGTH_LIMIT = 500;
+
+const TOKEN_LENGTH_LIMIT = 100;
+
+const TOKEN_COUNT_LIMIT = 10000;
+
+const TOKEN_OCCURRENCES_LIMIT = 1000;
+
+/**
+ * Token highlighting is only useful for code on-screen, so don't bother
+ * highlighting tokens that are further away than this threshold from where the
+ * user is hovering.
+ */
+const LINE_DISTANCE_THRESHOLD = 100;
+
+/**
+ * When a user hovers over a token in the diff, then this layer makes sure that
+ * all occurrences of this token are annotated with the 'token-highlight' css
+ * class. And removes that class when the user moves the mouse away from the
+ * token.
+ *
+ * The layer does not react to mouse events directly by adding a css class to
+ * the appropriate elements, but instead it just sets the currently highlighted
+ * token and notifies the diff renderer that certain lines must be re-rendered.
+ * And when that re-rendering happens the appropriate css class is added.
+ */
+export class TokenHighlightLayer implements DiffLayer {
+  /** The only listener is typically the renderer of gr-diff. */
+  private listeners: DiffLayerListener[] = [];
+
+  /** The currently highlighted token. */
+  private currentHighlight?: string;
+
+  /**
+   * The line of the currently highlighted token. We store this in order to
+   * re-render only relevant lines of the diff. Only lines visible on the screen
+   * need a highlight. For example in a file with 10,000 lines it is sufficient
+   * to just re-render the ~100 lines that are visible to the user.
+   *
+   * It is a known issue that we are only storing the line number on the side of
+   * where the user is hovering and we use that also to determine which line
+   * numbers to re-render on the other side, but it is non-trivial to look up or
+   * store a reliable mapping of line numbers, so we just accept this
+   * shortcoming with the reasoning that the user is mostly interested in the
+   * tokens on the side where they are hovering anyway.
+   *
+   * Another known issue is that we are not able to see past collapsed lines
+   * with the current implementation.
+   */
+  private currentHighlightLineNumber = 0;
+
+  /**
+   * Keeps track of where tokens occur in a file during rendering, so that it is
+   * easy to look up when processing mouse events.
+   */
+  private tokenToLinesLeft = new Map<string, Set<number>>();
+
+  private tokenToLinesRight = new Map<string, Set<number>>();
+
+  private updateTokenTask?: DelayedTask;
+
+  private readonly enabled = appContext.flagsService.isEnabled(
+    KnownExperimentId.TOKEN_HIGHLIGHTING
+  );
+
+  annotate(
+    el: HTMLElement,
+    _: HTMLElement,
+    line: GrDiffLine,
+    side: Side
+  ): void {
+    if (!this.enabled) return;
+    const text = el.textContent;
+    if (!text) return;
+    // Binary files encoded as text for example can have super long lines
+    // with super long tokens. Let's guard against against this scenario.
+    if (text.length > LINE_LENGTH_LIMIT) return;
+    let match;
+    let atLeastOneTokenMatched = false;
+    while ((match = tokenMatcher.exec(text))) {
+      const token = match[0];
+      const index = match.index;
+      const length = token.length;
+      // Binary files encoded as text for example can have super long lines
+      // with super long tokens. Let's guard against this scenario.
+      if (length > TOKEN_LENGTH_LIMIT) continue;
+      atLeastOneTokenMatched = true;
+      const css = token === this.currentHighlight ? CSS_HIGHLIGHT : CSS_TOKEN;
+      // We add the tk-* class so that we can look up the token later easily
+      // even if the token element was split up into multiple smaller nodes.
+      GrAnnotation.annotateElement(el, index, length, `tk-${token} ${css}`);
+      // We could try to detect whether we are re-rendering instead of initially
+      // rendering the line. Then we would not have to call storeLineForToken()
+      // again. But since the Set swallows the duplicates we don't care.
+      this.storeLineForToken(token, line, side);
+    }
+    if (atLeastOneTokenMatched) {
+      // These listeners do not have to be cleaned, because listeners are
+      // garbage collected along with the element itself once it is not attached
+      // to the DOM anymore and no references exist anymore.
+      el.addEventListener('mouseover', this.handleMouseOver);
+      el.addEventListener('mouseout', this.handleMouseOut);
+    }
+  }
+
+  private storeLineForToken(token: string, line: GrDiffLine, side: Side) {
+    const tokenToLines =
+      side === Side.LEFT ? this.tokenToLinesLeft : this.tokenToLinesRight;
+    // Just to make sure that we don't break down on large files.
+    if (tokenToLines.size > TOKEN_COUNT_LIMIT) return;
+    let numbers = tokenToLines.get(token);
+    if (!numbers) {
+      numbers = new Set<number>();
+      tokenToLines.set(token, numbers);
+    }
+    // Just to make sure that we don't break down on large files.
+    if (numbers.size > TOKEN_OCCURRENCES_LIMIT) return;
+    const lineNumber =
+      side === Side.LEFT ? line.beforeNumber : line.afterNumber;
+    numbers.add(Number(lineNumber));
+  }
+
+  private readonly handleMouseOut = (e: MouseEvent) => {
+    if (!this.currentHighlight) return;
+    if (this.interferesWithSelection(e)) return;
+    const el = this.findTokenAncestor(e?.target);
+    if (!el) return;
+    this.updateTokenHighlight(undefined, undefined);
+  };
+
+  private readonly handleMouseOver = (e: MouseEvent) => {
+    if (this.interferesWithSelection(e)) return;
+    const {line, token} = this.findTokenAncestor(e?.target);
+    if (!token) return;
+    const oldHighlight = this.currentHighlight;
+    const newHighlight = token;
+    if (!newHighlight || newHighlight === oldHighlight) return;
+    if (this.countOccurrences(newHighlight) <= 1) return;
+    this.updateTokenHighlight(line, newHighlight);
+  };
+
+  private interferesWithSelection(e: MouseEvent) {
+    if (e.buttons > 0) return true;
+    if (window.getSelection()?.type === 'Range') return true;
+    return false;
+  }
+
+  private updateTokenHighlight(
+    newLineNumber: number | undefined,
+    newHighlight: string | undefined
+  ) {
+    this.updateTokenTask = debounce(
+      this.updateTokenTask,
+      () => {
+        const oldHighlight = this.currentHighlight;
+        const oldLineNumber = this.currentHighlightLineNumber;
+        this.currentHighlight = newHighlight;
+        this.currentHighlightLineNumber = newLineNumber ?? 0;
+        this.notifyForToken(oldHighlight, oldLineNumber);
+        this.notifyForToken(newHighlight, newLineNumber ?? 0);
+      },
+      UPDATE_TOKEN_TASK_DELAY_MS
+    );
+  }
+
+  findTokenAncestor(
+    el?: EventTarget | Element | null
+  ): {
+    token?: string;
+    line: number;
+  } {
+    if (!(el instanceof Element)) return {line: 0, token: undefined};
+    if (
+      el.classList.contains(CSS_TOKEN) ||
+      el.classList.contains(CSS_HIGHLIGHT)
+    ) {
+      const tkClass = [...el.classList].find(c => c.startsWith('tk-'));
+      const line = lineNumberToNumber(getLineNumberByChild(el));
+      if (!line || !tkClass) return {line: 0, token: undefined};
+      return {line, token: tkClass.substring(3)};
+    }
+    if (el.tagName === 'TD') return {line: 0, token: undefined};
+    return this.findTokenAncestor(el.parentElement);
+  }
+
+  countOccurrences(token: string | undefined) {
+    if (!token) return 0;
+    const linesLeft = this.tokenToLinesLeft.get(token);
+    const linesRight = this.tokenToLinesRight.get(token);
+    return (linesLeft?.size ?? 0) + (linesRight?.size ?? 0);
+  }
+
+  notifyForToken(token: string | undefined, lineNumber: number) {
+    if (!token) return;
+    const linesLeft = this.tokenToLinesLeft.get(token);
+    linesLeft?.forEach(line => {
+      if (Math.abs(line - lineNumber) < LINE_DISTANCE_THRESHOLD) {
+        this.notifyListeners(line, Side.LEFT);
+      }
+    });
+    const linesRight = this.tokenToLinesRight.get(token);
+    linesRight?.forEach(line => {
+      if (Math.abs(line - lineNumber) < LINE_DISTANCE_THRESHOLD) {
+        this.notifyListeners(line, Side.RIGHT);
+      }
+    });
+  }
+
+  addListener(listener: DiffLayerListener) {
+    this.listeners.push(listener);
+  }
+
+  removeListener(listener: DiffLayerListener) {
+    this.listeners = this.listeners.filter(f => f !== listener);
+  }
+
+  notifyListeners(line: number, side: Side) {
+    for (const listener of this.listeners) {
+      listener(line, line, side);
+    }
+  }
+}
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.ts b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.ts
index 76e02f0..ca003f3 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.ts
@@ -28,7 +28,13 @@
 import {GrSelectionActionBox} from '../gr-selection-action-box/gr-selection-action-box';
 import {GrDiffBuilderElement} from '../gr-diff-builder/gr-diff-builder-element';
 import {FILE} from '../gr-diff/gr-diff-line';
-import {getRange, getSide} from '../gr-diff/gr-diff-utils';
+import {
+  getLineElByChild,
+  getLineNumberByChild,
+  getRange,
+  getSide,
+  getSideByLineEl,
+} from '../gr-diff/gr-diff-utils';
 import {debounce, DelayedTask} from '../../../utils/async-util';
 
 interface SidedRange {
@@ -356,11 +362,11 @@
   ): NormalizedPosition | null {
     let column;
     if (!node || !this.contains(node)) return null;
-    const lineEl = this.diffBuilder.getLineElByChild(node);
+    const lineEl = getLineElByChild(node);
     if (!lineEl) return null;
-    const side = this.diffBuilder.getSideByLineEl(lineEl);
+    const side = getSideByLineEl(lineEl);
     if (!side) return null;
-    const line = this.diffBuilder.getLineNumberByChild(lineEl);
+    const line = getLineNumberByChild(lineEl);
     if (!line || line === FILE || line === 'LOST') return null;
     const contentTd = this.diffBuilder.getContentTdByLineEl(lineEl);
     if (!contentTd) return null;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.js b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.js
index 07e83a8..18fbe9a 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.js
@@ -438,7 +438,7 @@
       const contentText = stubContent(140, 'left');
       const contentTd = contentText.parentElement;
 
-      emulateSelection(contentTd.previousElementSibling, 0,
+      emulateSelection(contentTd.parentElement, 0,
           contentText.firstChild, 2);
       assert.isFalse(!!element.selectedRange);
     });
@@ -584,21 +584,6 @@
       });
       assert.equal(side, 'right');
     });
-
-    test('_fixTripleClickSelection empty line', () => {
-      const startContent = stubContent(146, 'right');
-      const endContent = stubContent(165, 'left');
-      emulateSelection(startContent.firstChild, 0,
-          endContent.parentElement.previousElementSibling, 0);
-      const {range, side} = element.selectedRange;
-      assert.deepEqual(range, {
-        start_line: 146,
-        start_character: 0,
-        end_line: 146,
-        end_character: 84,
-      });
-      assert.equal(side, 'right');
-    });
   });
 });
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.ts b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.ts
index 3df2e18..b64f61d 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.ts
@@ -28,7 +28,12 @@
 import {DiffInfo} from '../../../types/diff';
 import {Side} from '../../../constants/constants';
 import {GrDiffBuilderElement} from '../gr-diff-builder/gr-diff-builder-element';
-import {getSide, isThreadEl} from '../gr-diff/gr-diff-utils';
+import {
+  getLineElByChild,
+  getSide,
+  getSideByLineEl,
+  isThreadEl,
+} from '../gr-diff/gr-diff-utils';
 
 /**
  * Possible CSS classes indicating the state of selection. Dynamically added/
@@ -110,7 +115,7 @@
     // Handle the down event on comment thread in Polymer 2
     const handled = this._handleDownOnRangeComment(target);
     if (handled) return;
-    const lineEl = this.diffBuilder.getLineElByChild(target);
+    const lineEl = getLineElByChild(target);
     const blameSelected = this._elementDescendedFromClass(target, 'blame');
     if (!lineEl && !blameSelected) {
       return;
@@ -125,7 +130,7 @@
         target,
         'gr-comment'
       );
-      const side = this.diffBuilder.getSideByLineEl(lineEl);
+      const side = getSideByLineEl(lineEl);
 
       targetClasses.push(
         side === 'left' ? SelectionClass.LEFT : SelectionClass.RIGHT
@@ -179,9 +184,9 @@
     if (this.classList.contains(SelectionClass.COMMENT)) {
       commentSelected = true;
     }
-    const lineEl = this.diffBuilder.getLineElByChild(target);
+    const lineEl = getLineElByChild(target);
     if (!lineEl) return;
-    const side = this.diffBuilder.getSideByLineEl(lineEl);
+    const side = getSideByLineEl(lineEl);
     const text = this._getSelectedText(side, commentSelected);
     if (text && e.clipboardData) {
       e.clipboardData.setData('Text', text);
@@ -224,9 +229,9 @@
       return this._getCommentLines(sel, side);
     }
     const range = normalize(sel.getRangeAt(0));
-    const startLineEl = this.diffBuilder.getLineElByChild(range.startContainer);
+    const startLineEl = getLineElByChild(range.startContainer);
     if (!startLineEl) return;
-    const endLineEl = this.diffBuilder.getLineElByChild(range.endContainer);
+    const endLineEl = getLineElByChild(range.endContainer);
     // Happens when triple click in side-by-side mode with other side empty.
     const endsAtOtherEmptySide =
       !endLineEl &&
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection_test.js b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection_test.js
index 5c9fe3f..8d7264c 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection_test.js
@@ -143,8 +143,8 @@
 
   test('applies selected-left on left side click', () => {
     element.classList.add('selected-right');
-    element._cachedDiffBuilder.getSideByLineEl.returns('left');
-    MockInteractions.down(element);
+    const lineNumberEl = element.querySelector('.lineNum.left');
+    MockInteractions.down(lineNumberEl);
     assert.isTrue(
         element.classList.contains('selected-left'), 'adds selected-left');
     assert.isFalse(
@@ -154,8 +154,8 @@
 
   test('applies selected-right on right side click', () => {
     element.classList.add('selected-left');
-    element._cachedDiffBuilder.getSideByLineEl.returns('right');
-    MockInteractions.down(element);
+    const lineNumberEl = element.querySelector('.lineNum.right');
+    MockInteractions.down(lineNumberEl);
     assert.isTrue(
         element.classList.contains('selected-right'), 'adds selected-right');
     assert.isFalse(
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 88960ab..ad2e9c0 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
@@ -98,7 +98,7 @@
 import {fireAlert, fireEvent, fireTitleChange} from '../../../utils/event-util';
 import {GerritView} from '../../../services/router/router-model';
 import {assertIsDefined} from '../../../utils/common-util';
-import {toggleClass} from '../../../utils/dom-util';
+import {toggleClass, getKeyboardEvent} from '../../../utils/dom-util';
 const ERR_REVIEW_STATUS = 'Couldn’t change file review status.';
 const MSG_LOADING_BLAME = 'Loading blame...';
 const MSG_LOADED_BLAME = 'Blame loaded';
@@ -593,7 +593,7 @@
   _handlePrevFile(e: CustomKeyboardEvent) {
     if (this.shouldSuppressKeyboardShortcut(e)) return;
     // Check for meta key to avoid overriding native chrome shortcut.
-    if (this.getKeyboardEvent(e).metaKey) return;
+    if (getKeyboardEvent(e).metaKey) return;
     if (!this._path) return;
     if (!this._fileList) return;
 
@@ -604,7 +604,7 @@
   _handleNextFile(e: CustomKeyboardEvent) {
     if (this.shouldSuppressKeyboardShortcut(e)) return;
     // Check for meta key to avoid overriding native chrome shortcut.
-    if (this.getKeyboardEvent(e).metaKey) return;
+    if (getKeyboardEvent(e).metaKey) return;
     if (!this._path) return;
     if (!this._fileList) return;
 
@@ -1791,12 +1791,9 @@
     if (!this._fileList) return;
     if (!this._patchRange) return;
     if (!this._change) return;
-    const hasComment = (path: string) => {
-      return (
-        this._changeComments?.getCommentsForPath(path, this._patchRange!)
-          ?.length ?? 0 > 0
-      );
-    };
+    const hasComment = (path: string) =>
+      this._changeComments?.getCommentsForPath(path, this._patchRange!)
+        ?.length ?? 0 > 0;
     const filesWithComments = this._fileList.filter(
       file => file === this._path || hasComment(file)
     );
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_html.ts b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_html.ts
index e275d84..30c6f49 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_html.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_html.ts
@@ -302,9 +302,7 @@
             items="[[_computeDownloadDropdownLinks(_change.project, _changeNum, _patchRange, _path, _diff)]]"
             horizontal-align="left"
           >
-            <span class="downloadTitle">
-              Download
-            </span>
+            <span class="downloadTitle"> Download </span>
           </gr-dropdown>
         </span>
       </div>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-utils.ts b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-utils.ts
index 0ca929a..96fbd8d 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-utils.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-utils.ts
@@ -43,6 +43,36 @@
   return range.end_line - range.start_line > 10;
 }
 
+export function getLineNumberByChild(node?: Node) {
+  return getLineNumber(getLineElByChild(node));
+}
+
+export function lineNumberToNumber(lineNumber?: LineNumber | null): number {
+  if (!lineNumber) return 0;
+  if (lineNumber === 'LOST') return 0;
+  if (lineNumber === 'FILE') return 0;
+  return lineNumber;
+}
+
+export function getLineElByChild(node?: Node): HTMLElement | null {
+  while (node) {
+    if (node instanceof Element) {
+      if (node.classList.contains('lineNum')) {
+        return node as HTMLElement;
+      }
+      if (node.classList.contains('section')) {
+        return null;
+      }
+    }
+    node = node.previousSibling ?? node.parentElement ?? undefined;
+  }
+  return null;
+}
+
+export function getSideByLineEl(lineEl: Element) {
+  return lineEl.classList.contains(Side.RIGHT) ? Side.RIGHT : Side.LEFT;
+}
+
 export function getLineNumber(lineEl?: Element | null): LineNumber | null {
   if (!lineEl) return null;
   const lineNumberStr = lineEl.getAttribute('data-value');
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.ts b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.ts
index 41dd159..3b76698 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.ts
@@ -29,6 +29,7 @@
 import {LineNumber} from './gr-diff-line';
 import {
   getLine,
+  getLineElByChild,
   getLineNumber,
   getRange,
   getSide,
@@ -546,7 +547,7 @@
       el.classList.contains('content') ||
       el.classList.contains('contentText')
     ) {
-      const target = this.$.diffBuilder.getLineElByChild(el);
+      const target = getLineElByChild(el);
       if (target) {
         this._selectLine(target);
       }
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_html.ts b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_html.ts
index a93d5b5..059b0ee 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_html.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_html.ts
@@ -605,6 +605,10 @@
       border: 1px solid var(--diff-context-control-border-color);
       text-align: center;
     }
+
+    .token-highlight {
+      background-color: var(--token-highlighting-color, #fffd54);
+    }
   </style>
   <style include="gr-syntax-theme">
     /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.js b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.js
index 86946a6..53a2915 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.js
@@ -472,10 +472,12 @@
     test('_handleTap content', done => {
       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');
-      sinon.stub(element.$.diffBuilder, 'getLineElByChild')
-          .callsFake(() => lineEl);
 
       content.className = 'content';
       content.addEventListener('click', e => {
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.ts b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.ts
index 5746d73..77eccca 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.ts
+++ b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.ts
@@ -170,9 +170,9 @@
   }
 
   _hideAllDialogs() {
-    const dialogs = this.root!.querySelectorAll('.dialog') as NodeListOf<
-      GrDialog
-    >;
+    const dialogs = this.root!.querySelectorAll(
+      '.dialog'
+    ) as NodeListOf<GrDialog>;
     for (const dialog of dialogs) {
       this._closeDialog(dialog);
     }
diff --git a/polygerrit-ui/app/elements/gr-app-element.ts b/polygerrit-ui/app/elements/gr-app-element.ts
index 20d1801..e96f6e4 100644
--- a/polygerrit-ui/app/elements/gr-app-element.ts
+++ b/polygerrit-ui/app/elements/gr-app-element.ts
@@ -219,6 +219,10 @@
 
   constructor() {
     super();
+    // We just want to instantiate this service somewhere. It is reacting to
+    // model changes and updates the config model, but at the moment the service
+    // is not called from anywhere.
+    appContext.configService;
     this._bindKeyboardShortcuts();
     document.addEventListener(EventType.PAGE_ERROR, e => {
       this._handlePageError(e);
diff --git a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_html.ts b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_html.ts
index 01ebfbd..6ca484d 100644
--- a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_html.ts
@@ -41,9 +41,7 @@
     <section class$="[[_hideAvatarChangeUrl(_avatarChangeUrl)]]">
       <span class="title"></span>
       <span class="value">
-        <a href$="[[_avatarChangeUrl]]">
-          Change avatar
-        </a>
+        <a href$="[[_avatarChangeUrl]]"> Change avatar </a>
       </span>
     </section>
     <section>
diff --git a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_html.ts b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_html.ts
index 59203d3..887382e 100644
--- a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_html.ts
@@ -84,9 +84,7 @@
       >
         Agreement already submitted.
       </div>
-      <div class="agreementsUrl">
-        [[item.description]]
-      </div>
+      <div class="agreementsUrl">[[item.description]]</div>
     </template>
     <div
       id="claNewAgreement"
diff --git a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_html.ts b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_html.ts
index 0ae3490..5f98a82 100644
--- a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_html.ts
@@ -46,9 +46,7 @@
         <template is="dom-repeat" items="[[_groups]]">
           <tr>
             <td class="nameColumn">
-              <a href$="[[_computeGroupPath(item)]]">
-                [[item.name]]
-              </a>
+              <a href$="[[_computeGroupPath(item)]]"> [[item.name]] </a>
             </td>
             <td>[[item.description]]</td>
             <td class="visibleCell">[[_computeVisibleToAll(item)]]</td>
diff --git a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_html.ts b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_html.ts
index 34af7eb..ef5d72f 100644
--- a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_html.ts
@@ -64,9 +64,7 @@
             filter="filterIdentities"
           >
             <tr>
-              <td class="statusColumn">
-                [[_computeIsTrusted(item.trusted)]]
-              </td>
+              <td class="statusColumn">[[_computeIsTrusted(item.trusted)]]</td>
               <td class="emailAddressColumn">[[item.email_address]]</td>
               <td class="identityColumn">
                 [[_computeIdentity(item.identity)]]
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts
index 492561f..f9f7a93 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts
@@ -74,6 +74,7 @@
   'email_strategy',
   'diff_view',
   'publish_comments_on_push',
+  'disable_keyboard_shortcuts',
   'work_in_progress_by_default',
   'default_base_for_merges',
   'signed_off_by',
@@ -112,6 +113,7 @@
     workInProgressByDefault: HTMLInputElement;
     showSizeBarsInFileList: HTMLInputElement;
     publishCommentsOnPush: HTMLInputElement;
+    disableKeyboardShortcuts: HTMLInputElement;
     relativeDateInChangeTable: HTMLInputElement;
   };
 }
@@ -338,9 +340,7 @@
 
   _cloneMenu(prefs: TopMenuItemInfo[]) {
     // eslint-disable-next-line @typescript-eslint/no-unused-vars
-    return prefs.map(({id, ...item}) => {
-      return item;
-    });
+    return prefs.map(({id, ...item}) => item);
   }
 
   @observe('_localChangeTableColumns', '_showNumber')
@@ -380,6 +380,13 @@
     );
   }
 
+  _handleDisableKeyboardShortcutsChanged() {
+    this.set(
+      '_localPrefs.disable_keyboard_shortcuts',
+      this.$.disableKeyboardShortcuts.checked
+    );
+  }
+
   _handleWorkInProgressByDefault() {
     this.set(
       '_localPrefs.work_in_progress_by_default',
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_html.ts b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_html.ts
index 0bb6f09..8b000e9 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_html.ts
@@ -75,14 +75,10 @@
           <li><a href="#HTTPCredentials">HTTP Credentials</a></li>
         </template>
         <li hidden$="[[!_serverConfig.sshd]]">
-          <a href="#SSHKeys">
-            SSH Keys
-          </a>
+          <a href="#SSHKeys"> SSH Keys </a>
         </li>
         <li hidden$="[[!_serverConfig.receive.enable_signed_push]]">
-          <a href="#GPGKeys">
-            GPG Keys
-          </a>
+          <a href="#GPGKeys"> GPG Keys </a>
         </li>
         <li><a href="#Groups">Groups</a></li>
         <li><a href="#Identities">Identities</a></li>
@@ -184,9 +180,9 @@
               <select id="emailNotificationsSelect">
                 <option value="CC_ON_OWN_COMMENTS">Every comment</option>
                 <option value="ENABLED">Only comments left by others</option>
-                <option value="ATTENTION_SET_ONLY"
-                  >Only when I am in the attention set</option
-                >
+                <option value="ATTENTION_SET_ONLY">
+                  Only when I am in the attention set
+                </option>
                 <option value="DISABLED">None</option>
               </select>
             </gr-select>
@@ -278,6 +274,19 @@
           </span>
         </section>
         <section>
+          <label for="disableKeyboardShortcuts" class="title"
+            >Disable all keyboard shortcuts</label
+          >
+          <span class="value">
+            <input
+              id="disableKeyboardShortcuts"
+              type="checkbox"
+              checked$="[[_localPrefs.disable_keyboard_shortcuts]]"
+              on-change="_handleDisableKeyboardShortcutsChanged"
+            />
+          </span>
+        </section>
+        <section>
           <label for="insertSignedOff" class="title">
             Insert Signed-off-by Footer For Inline Edit Changes
           </label>
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts
index b8c2c21..1ff5350 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts
@@ -61,9 +61,7 @@
   value: string;
 }
 
-export type AutocompleteCommitEvent = CustomEvent<
-  AutocompleteCommitEventDetail
->;
+export type AutocompleteCommitEvent = CustomEvent<AutocompleteCommitEventDetail>;
 
 @customElement('gr-autocomplete')
 export class GrAutocomplete extends KeyboardShortcutMixin(PolymerElement) {
diff --git a/polygerrit-ui/app/elements/shared/gr-button/gr-button.ts b/polygerrit-ui/app/elements/shared/gr-button/gr-button.ts
index 6a7c05b..a25a3dc 100644
--- a/polygerrit-ui/app/elements/shared/gr-button/gr-button.ts
+++ b/polygerrit-ui/app/elements/shared/gr-button/gr-button.ts
@@ -20,8 +20,12 @@
 import {customElement, property, computed, observe} from '@polymer/decorators';
 import {htmlTemplate} from './gr-button_html';
 import {TooltipMixin} from '../../../mixins/gr-tooltip-mixin/gr-tooltip-mixin';
-import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
-import {PolymerEvent, getEventPath} from '../../../utils/dom-util';
+import {
+  PolymerEvent,
+  getEventPath,
+  getKeyboardEvent,
+  isModifierPressed,
+} from '../../../utils/dom-util';
 import {appContext} from '../../../services/app-context';
 import {ReportingService} from '../../../services/gr-reporting/gr-reporting';
 import {CustomKeyboardEvent} from '../../../types/events';
@@ -33,9 +37,7 @@
 }
 
 @customElement('gr-button')
-export class GrButton extends KeyboardShortcutMixin(
-  TooltipMixin(PolymerElement)
-) {
+export class GrButton extends TooltipMixin(PolymerElement) {
   static get template() {
     return htmlTemplate;
   }
@@ -121,10 +123,10 @@
   }
 
   _handleKeydown(e: CustomKeyboardEvent) {
-    if (this.modifierPressed(e)) {
+    if (isModifierPressed(e)) {
       return;
     }
-    e = this.getKeyboardEvent(e);
+    e = getKeyboardEvent(e);
     // Handle `enter`, `space`.
     if (e.keyCode === 13 || e.keyCode === 32) {
       e.preventDefault();
diff --git a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.ts b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.ts
index 2b66af8..01ca57a 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.ts
+++ b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.ts
@@ -20,7 +20,6 @@
 import {htmlTemplate} from './gr-change-star_html';
 import {customElement, property} from '@polymer/decorators';
 import {ChangeInfo} from '../../../types/common';
-import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
 import {fireAlert} from '../../../utils/event-util';
 
 declare global {
@@ -35,7 +34,7 @@
 }
 
 @customElement('gr-change-star')
-export class GrChangeStar extends KeyboardShortcutMixin(PolymerElement) {
+export class GrChangeStar extends PolymerElement {
   static get template() {
     return htmlTemplate;
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.ts b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.ts
index 1fd019f..f18f121 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.ts
+++ b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.ts
@@ -19,6 +19,10 @@
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-change-status_html';
 import {customElement, property} from '@polymer/decorators';
+import {GerritNav} from '../../core/gr-navigation/gr-navigation';
+import {getRevertCommitHash} from '../../../utils/message-util';
+import {ChangeInfo} from '../../../types/common';
+import {ParsedChangeInfo} from '../../../types/types';
 
 enum ChangeStates {
   MERGED = 'Merged',
@@ -26,6 +30,7 @@
   MERGE_CONFLICT = 'Merge Conflict',
   WIP = 'WIP',
   PRIVATE = 'Private',
+  REVERT_CREATED = 'Revert Created',
 }
 
 const WIP_TOOLTIP =
@@ -51,6 +56,9 @@
   @property({type: Boolean, reflectToAttribute: true})
   flat = false;
 
+  @property({type: Object})
+  change?: ChangeInfo | ParsedChangeInfo;
+
   @property({type: String, observer: '_updateChipDetails'})
   status?: ChangeStates;
 
@@ -68,6 +76,17 @@
     return str ? str.toLowerCase().replace(/\s/g, '-') : '';
   }
 
+  hasStatusLink(status: ChangeStates) {
+    return status === ChangeStates.REVERT_CREATED;
+  }
+
+  getStatusLink(change?: ParsedChangeInfo) {
+    if (!change) return;
+    const revertCommit = getRevertCommitHash(change.messages);
+    if (!revertCommit) return;
+    return GerritNav.getUrlForSearchQuery(revertCommit);
+  }
+
   _updateChipDetails(status?: ChangeStates, previousStatus?: ChangeStates) {
     if (previousStatus) {
       this.classList.remove(this._toClassName(previousStatus));
diff --git a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_html.ts b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_html.ts
index 542d8be..379c3f3 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_html.ts
@@ -52,6 +52,13 @@
       background-color: var(--status-ready);
       color: var(--status-ready);
     }
+    :host(.revert-created) .chip {
+      background-color: var(--status-revert-created);
+      color: var(--status-revert-created);
+    }
+    .status-link {
+      text-decoration: none;
+    }
     :host(.custom) .chip {
       background-color: var(--status-custom);
       color: var(--status-custom);
@@ -70,8 +77,17 @@
     title="[[tooltipText]]"
     max-width="40em"
   >
-    <div class="chip" aria-label$="Label: [[status]]">
-      [[_computeStatusString(status)]]
-    </div>
+    <template is="dom-if" if="[[hasStatusLink(status)]]">
+      <a class="status-link" href="[[getStatusLink(change)]]">
+        <div class="chip" aria-label$="Label: [[status]]">
+          [[_computeStatusString(status)]]
+        </div>
+      </a>
+    </template>
+    <template is="dom-if" if="[[!hasStatusLink(status)]]">
+      <div class="chip" aria-label$="Label: [[status]]">
+        [[_computeStatusString(status)]]
+      </div>
+    </template>
   </gr-tooltip-content>
 `;
diff --git a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_test.js b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_test.js
index 16fc664..4ef97c9 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_test.js
@@ -37,6 +37,7 @@
 
   test('WIP', () => {
     element.status = 'WIP';
+    flush();
     assert.equal(element.shadowRoot
         .querySelector('.chip').innerText, 'Work in Progress');
     assert.equal(element.tooltipText, WIP_TOOLTIP);
@@ -46,6 +47,7 @@
   test('WIP flat', () => {
     element.flat = true;
     element.status = 'WIP';
+    flush();
     assert.equal(element.shadowRoot
         .querySelector('.chip').innerText, 'WIP');
     assert.isDefined(element.tooltipText);
@@ -55,6 +57,7 @@
 
   test('merged', () => {
     element.status = 'Merged';
+    flush();
     assert.equal(element.shadowRoot
         .querySelector('.chip').innerText, element.status);
     assert.equal(element.tooltipText, '');
@@ -63,6 +66,7 @@
 
   test('abandoned', () => {
     element.status = 'Abandoned';
+    flush();
     assert.equal(element.shadowRoot
         .querySelector('.chip').innerText, element.status);
     assert.equal(element.tooltipText, '');
@@ -71,6 +75,7 @@
 
   test('merge conflict', () => {
     element.status = 'Merge Conflict';
+    flush();
     assert.equal(element.shadowRoot
         .querySelector('.chip').innerText, element.status);
     assert.equal(element.tooltipText, MERGE_CONFLICT_TOOLTIP);
@@ -79,6 +84,7 @@
 
   test('private', () => {
     element.status = 'Private';
+    flush();
     assert.equal(element.shadowRoot
         .querySelector('.chip').innerText, element.status);
     assert.equal(element.tooltipText, PRIVATE_TOOLTIP);
@@ -87,6 +93,7 @@
 
   test('active', () => {
     element.status = 'Active';
+    flush();
     assert.equal(element.shadowRoot
         .querySelector('.chip').innerText, element.status);
     assert.equal(element.tooltipText, '');
@@ -95,6 +102,7 @@
 
   test('ready to submit', () => {
     element.status = 'Ready to submit';
+    flush();
     assert.equal(element.shadowRoot
         .querySelector('.chip').innerText, element.status);
     assert.equal(element.tooltipText, '');
@@ -103,10 +111,12 @@
 
   test('updating status removes the previous class', () => {
     element.status = 'Private';
+    flush();
     assert.isTrue(element.classList.contains('private'));
     assert.isFalse(element.classList.contains('wip'));
 
     element.status = 'WIP';
+    flush();
     assert.isFalse(element.classList.contains('private'));
     assert.isTrue(element.classList.contains('wip'));
   });
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 6d376e5..5b70cb4 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
@@ -239,6 +239,7 @@
         // remaining space after comment card has rendered
         line_wrapping: true,
       };
+      this.syntaxLayer.setEnabled(!!prefs.syntax_highlighting);
     });
     this._setInitialExpandedState();
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.ts b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.ts
index 35b0d8c..64f5ad8 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.ts
@@ -156,9 +156,7 @@
       ];
       const commentElStub = sinon
         .stub(element, '_commentElWithDraftID')
-        .callsFake(() => {
-          return new GrComment();
-        });
+        .callsFake(() => new GrComment());
       const addDraftStub = sinon.stub(element, 'addDraft');
 
       element.addOrEditDraft(123);
@@ -171,9 +169,7 @@
       element.comments = [];
       const commentElStub = sinon
         .stub(element, '_commentElWithDraftID')
-        .callsFake(() => {
-          return new GrComment();
-        });
+        .callsFake(() => new GrComment());
       const addDraftStub = sinon.stub(element, 'addDraft');
 
       element.addOrEditDraft(123);
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_html.ts b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_html.ts
index 158e8574..aad8c98 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_html.ts
@@ -485,9 +485,7 @@
         on-confirm="_handleConfirmDiscard"
         on-cancel="_closeConfirmDiscardOverlay"
       >
-        <div class="header" slot="header">
-          Discard comment
-        </div>
+        <div class="header" slot="header">Discard comment</div>
         <div class="main" slot="main">
           Are you sure you want to discard this draft comment?
         </div>
diff --git a/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences_html.ts b/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences_html.ts
index 246d192..ed3d695 100644
--- a/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences_html.ts
@@ -189,9 +189,9 @@
             >
               <option value="IGNORE_NONE">None</option>
               <option value="IGNORE_TRAILING">Trailing</option>
-              <option value="IGNORE_LEADING_AND_TRAILING"
-                >Leading &amp; trailing</option
-              >
+              <option value="IGNORE_LEADING_AND_TRAILING">
+                Leading &amp; trailing
+              </option>
               <option value="IGNORE_ALL">All</option>
             </select>
           </gr-select>
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.ts b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.ts
index 4e61bcd..a4a6fe3 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.ts
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.ts
@@ -102,6 +102,10 @@
   @property({type: Number})
   verticalOffset = 40;
 
+  /** Propagates/Reflects the `opened` property of the <iron-dropdown> */
+  @property({type: Boolean, notify: true})
+  opened = false;
+
   /**
    * List the IDs of dropdown buttons to be disabled. (Note this only
    * disables buttons and not link entries.)
@@ -197,6 +201,10 @@
     this._close();
   }
 
+  handleOpenedChanged(e: CustomEvent) {
+    this.opened = e.detail.value;
+  }
+
   /**
    * Handle a click on the button to open the dropdown.
    */
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_html.ts b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_html.ts
index aaeb47c..e754c9c 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_html.ts
@@ -28,6 +28,8 @@
     .dropdown-content {
       background-color: var(--dropdown-background-color);
       box-shadow: var(--elevation-level-2);
+      min-width: 112px;
+      max-width: 280px;
     }
     gr-button {
       vertical-align: top;
@@ -104,6 +106,7 @@
     allow-outside-scroll="true"
     horizontal-align="[[horizontalAlign]]"
     on-click="_handleDropdownClick"
+    on-opened-changed="handleOpenedChanged"
   >
     <div class="dropdown-content" slot="dropdown-content">
       <ul>
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.ts b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.ts
index c758455..1702b4a 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.ts
+++ b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.ts
@@ -31,6 +31,7 @@
   AutocompleteQuery,
   GrAutocomplete,
 } from '../gr-autocomplete/gr-autocomplete';
+import {getKeyboardEvent} from '../../../utils/dom-util';
 
 const AWAIT_MAX_ITERS = 10;
 const AWAIT_STEP = 5;
@@ -203,7 +204,7 @@
   }
 
   _handleEnter(e: CustomKeyboardEvent) {
-    e = this.getKeyboardEvent(e);
+    e = getKeyboardEvent(e);
     const target = (dom(e) as EventApi).rootTarget;
     if (target === this._nativeInput) {
       e.preventDefault();
@@ -212,7 +213,7 @@
   }
 
   _handleEsc(e: CustomKeyboardEvent) {
-    e = this.getKeyboardEvent(e);
+    e = getKeyboardEvent(e);
     const target = (dom(e) as EventApi).rootTarget;
     if (target === this._nativeInput) {
       e.preventDefault();
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.ts b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.ts
index 7bff441..abd4469 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.ts
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.ts
@@ -135,9 +135,7 @@
   _getReviewerState(account: AccountInfo, change: ChangeInfo) {
     if (
       change.reviewers[ReviewerState.REVIEWER]?.some(
-        (reviewer: AccountInfo) => {
-          return reviewer._account_id === account._account_id;
-        }
+        (reviewer: AccountInfo) => reviewer._account_id === account._account_id
       )
     ) {
       return ReviewerState.REVIEWER;
diff --git a/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.ts b/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.ts
index 8803557..dc27a49 100644
--- a/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.ts
+++ b/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.ts
@@ -134,6 +134,12 @@
       <g id="arrowDropUp"><path d="M0 0h24v24H0z" fill="none"/><path d="M7 14l5-5 5 5z"/></g>
       <!-- This is just a placeholder, i.e. an empty icon that has the same size as a normal icon. -->
       <g id="placeholder"><path d="M0 0h24v24H0z" fill="none"/></g>
+      <!-- This SVG is a copy from material.io https://material.io/icons/#insert_photo-->
+      <g id="insert-photo"><path d="M0 0h24v24H0z" fill="none"/><path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/></g>
+      <!-- This SVG is a copy from material.io https://material.io/icons/#download-->
+      <g id="download"><path d="M0 0h24v24H0z" fill="none"/><path d="M5,20h14v-2H5V20z M19,9h-4V3H9v6H5l7,7L19,9z"/></g>
+      <!-- This SVG is a copy from material.io https://material.io/icons/#system_update-->
+      <g id="system-update"><path d="M0 0h24v24H0z" fill="none"/><path d="M17 1.01L7 1c-1.1 0-2 .9-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-1.99-2-1.99zM17 19H7V5h10v14zm-1-6h-3V8h-2v5H8l4 4 4-4z"/></g>
     </defs>
   </svg>
 </iron-iconset-svg>`;
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts
index 145883b..ef0367f 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts
@@ -275,7 +275,8 @@
 }
 
 @customElement('gr-rest-api-interface')
-export class GrRestApiInterface extends PolymerElement
+export class GrRestApiInterface
+  extends PolymerElement
   implements RestApiService {
   readonly _cache = siteBasedCache; // Shared across instances.
 
@@ -611,9 +612,9 @@
     };
     return this._restApiHelper.send(req).then(response => {
       if (response?.ok) {
-        return (this.getResponseObject(response) as unknown) as Promise<
-          GroupInfo
-        >;
+        return (this.getResponseObject(
+          response
+        ) as unknown) as Promise<GroupInfo>;
       }
       return undefined;
     });
@@ -2830,9 +2831,9 @@
         if (!response || (response.status < 200 && response.status >= 300)) {
           return Promise.reject(new Error('error'));
         }
-        return (this.getResponseObject(response) as unknown) as Promise<
-          SshKeyInfo
-        >;
+        return (this.getResponseObject(
+          response
+        ) as unknown) as Promise<SshKeyInfo>;
       })
       .then(obj => {
         if (!obj || !obj.valid) {
diff --git a/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.ts b/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.ts
index 746d101..837a795 100644
--- a/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.ts
+++ b/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.ts
@@ -103,10 +103,12 @@
 import {property} from '@polymer/decorators';
 import {PolymerElement} from '@polymer/polymer';
 import {Constructor} from '../../utils/common-util';
+import {getKeyboardEvent, isModifierPressed} from '../../utils/dom-util';
 import {
   CustomKeyboardEvent,
   ShortcutTriggeredEventDetail,
 } from '../../types/events';
+import {appContext} from '../../services/app-context';
 
 /** Enum for all special shortcuts */
 export enum SPECIAL_SHORTCUT {
@@ -530,19 +532,6 @@
   'Emoji dropdown'
 );
 
-// Must be declared outside behavior implementation to be accessed inside
-// behavior functions.
-
-function getKeyboardEvent(e: CustomKeyboardEvent): CustomKeyboardEvent {
-  const event = dom(e.detail ? e.detail.keyboardEvent : e);
-  // TODO(TS): worth checking if this still holds or not, if no, remove this.
-  // When e is a keyboardEvent, e.event is not null.
-  if ('event' in event && (event as CustomKeyboardEvent).event) {
-    return (event as CustomKeyboardEvent).event;
-  }
-  return event as CustomKeyboardEvent;
-}
-
 /**
  * Shortcut manager, holds all hosts, bindings and listeners.
  */
@@ -761,16 +750,6 @@
 
 const shortcutManager = new ShortcutManager();
 
-/**
- * Enum for supported modifiers.
- */
-export enum Modifier {
-  SHIFT_KEY = 'shiftKey',
-  CTRL_KEY = 'ctrlKey',
-  META_KEY = 'metaKey',
-  // Add when you need it
-}
-
 interface IronA11yKeysMixinConstructor {
   // Note: this is needed to have same interface as other mixins
   // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -805,6 +784,10 @@
 
       ShortcutSection = ShortcutSection;
 
+      private _disableKeyboardShortcuts = false;
+
+      private readonly restApiService = appContext.restApiService;
+
       modifierPressed(event: CustomKeyboardEvent) {
         /* We are checking for g/v as modifiers pressed. There are cases such as
          * pressing v and then /, where we want the handler for / to be triggered.
@@ -812,20 +795,12 @@
          */
         const e = getKeyboardEvent(event);
         return (
-          e.altKey ||
-          e.ctrlKey ||
-          e.metaKey ||
-          e.shiftKey ||
-          !!this._inGoKeyMode() ||
-          !!this.inVKeyMode()
+          isModifierPressed(e) || !!this._inGoKeyMode() || !!this.inVKeyMode()
         );
       }
 
-      isModifierPressed(e: CustomKeyboardEvent, modifier: Modifier) {
-        return getKeyboardEvent(e)[modifier];
-      }
-
       shouldSuppressKeyboardShortcut(event: CustomKeyboardEvent) {
+        if (this._disableKeyboardShortcuts) return true;
         const e = getKeyboardEvent(event);
         // TODO(TS): maybe override the EventApi, narrow it down to Element always
         const target = (dom(e) as EventApi).rootTarget as Element;
@@ -927,6 +902,13 @@
       /** @override */
       connectedCallback() {
         super.connectedCallback();
+
+        this.restApiService.getPreferences().then(prefs => {
+          if (prefs?.disable_keyboard_shortcuts) {
+            this._disableKeyboardShortcuts = true;
+          }
+        });
+
         const shortcuts = shortcutManager.attachHost(this);
         if (!shortcuts) {
           return;
@@ -1066,14 +1048,13 @@
 // This is a workaround
 export const KeyboardShortcutMixin = <T extends Constructor<PolymerElement>>(
   superClass: T
-): T & Constructor<KeyboardShortcutMixinInterface> => {
-  return InternalKeyboardShortcutMixin(
+): T & Constructor<KeyboardShortcutMixinInterface> =>
+  InternalKeyboardShortcutMixin(
     // TODO(TS): mixinBehaviors in some lib is returning: `new () => T` instead
     // which will fail the type check due to missing IronA11yKeysBehavior interface
     // eslint-disable-next-line @typescript-eslint/no-explicit-any
     mixinBehaviors([IronA11yKeysBehavior], superClass) as any
   );
-};
 
 /** The interface corresponding to KeyboardShortcutMixin */
 export interface KeyboardShortcutMixinInterface {
@@ -1088,8 +1069,6 @@
   bindShortcut(shortcut: Shortcut, ...bindings: string[]): void;
   shouldSuppressKeyboardShortcut(event: CustomKeyboardEvent): boolean;
   modifierPressed(event: CustomKeyboardEvent): boolean;
-  isModifierPressed(event: CustomKeyboardEvent, modifier: Modifier): boolean;
-  getKeyboardEvent(e: CustomKeyboardEvent): CustomKeyboardEvent;
   addKeyboardShortcutDirectoryListener(listener: ShortcutListener): void;
   removeKeyboardShortcutDirectoryListener(listener: ShortcutListener): void;
   // TODO(TS): Remove underscore. Apparently not a private method.
diff --git a/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin_test.js b/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin_test.js
index 180dbe7..b22b8d8 100644
--- a/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin_test.js
+++ b/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin_test.js
@@ -377,27 +377,6 @@
     assert.isTrue(spy.lastCall.returnValue);
   });
 
-  test('isModifierPressed returns accurate value', () => {
-    const spy = sinon.spy(element, 'isModifierPressed');
-    element._handleKey = e => {
-      element.isModifierPressed(e, 'shiftKey');
-    };
-    MockInteractions.keyDownOn(element, 75, 'shift', 'k');
-    assert.isTrue(spy.lastCall.returnValue);
-    MockInteractions.keyDownOn(element, 75, null, 'k');
-    assert.isFalse(spy.lastCall.returnValue);
-    MockInteractions.keyDownOn(element, 75, 'ctrl', 'k');
-    assert.isFalse(spy.lastCall.returnValue);
-    MockInteractions.keyDownOn(element, 75, null, 'k');
-    assert.isFalse(spy.lastCall.returnValue);
-    MockInteractions.keyDownOn(element, 75, 'meta', 'k');
-    assert.isFalse(spy.lastCall.returnValue);
-    MockInteractions.keyDownOn(element, 75, null, 'k');
-    assert.isFalse(spy.lastCall.returnValue);
-    MockInteractions.keyDownOn(element, 75, 'alt', 'k');
-    assert.isFalse(spy.lastCall.returnValue);
-  });
-
   suite('GO_KEY timing', () => {
     let handlerStub;
 
diff --git a/polygerrit-ui/app/package.json b/polygerrit-ui/app/package.json
index e454850..c943bff 100644
--- a/polygerrit-ui/app/package.json
+++ b/polygerrit-ui/app/package.json
@@ -5,11 +5,11 @@
   "dependencies": {
     "@polymer/decorators": "^3.0.0",
     "@polymer/font-roboto-local": "^3.0.2",
-    "@polymer/iron-a11y-announcer": "^3.0.1",
+    "@polymer/iron-a11y-announcer": "^3.1.0",
     "@polymer/iron-a11y-keys-behavior": "^3.0.1",
     "@polymer/iron-autogrow-textarea": "^3.0.3",
     "@polymer/iron-dropdown": "^3.0.1",
-    "@polymer/iron-fit-behavior": "^3.0.2",
+    "@polymer/iron-fit-behavior": "^3.1.0",
     "@polymer/iron-icon": "^3.0.1",
     "@polymer/iron-iconset-svg": "^3.0.1",
     "@polymer/iron-input": "^3.0.1",
@@ -17,11 +17,11 @@
     "@polymer/iron-selector": "^3.0.1",
     "@polymer/paper-button": "^3.0.1",
     "@polymer/paper-card": "^3.0.1",
-    "@polymer/paper-checkbox": "3.0.1",
+    "@polymer/paper-checkbox": "^3.1.0",
     "@polymer/paper-dialog": "^3.0.1",
     "@polymer/paper-dialog-behavior": "^3.0.1",
     "@polymer/paper-dialog-scrollable": "^3.0.1",
-    "@polymer/paper-dropdown-menu": "3.0.1",
+    "@polymer/paper-dropdown-menu": "^3.2.0",
     "@polymer/paper-input": "^3.2.1",
     "@polymer/paper-item": "^3.0.1",
     "@polymer/paper-listbox": "^3.0.1",
@@ -31,14 +31,14 @@
     "@polymer/paper-tooltip": "^3.0.1",
     "@polymer/polymer": "^3.4.1",
     "@types/resize-observer-browser": "^0.1.5",
-    "@webcomponents/shadycss": "^1.9.2",
+    "@webcomponents/shadycss": "^1.10.2",
     "@webcomponents/webcomponentsjs": "^1.3.3",
     "ba-linkify": "file:../../lib/ba-linkify/src/",
     "lit-element": "^2.4.0",
-    "page": "^1.11.5",
+    "page": "^1.11.6",
     "polymer-bridges": "file:../../polymer-bridges/",
     "polymer-resin": "^2.0.1",
-    "rxjs": "^6.6.2",
+    "rxjs": "^6.6.7",
     "shadow-selection-polyfill": "^1.1.0"
   },
   "license": "Apache-2.0",
diff --git a/polygerrit-ui/app/services/app-context-init.ts b/polygerrit-ui/app/services/app-context-init.ts
index 479ab88..dab894e 100644
--- a/polygerrit-ui/app/services/app-context-init.ts
+++ b/polygerrit-ui/app/services/app-context-init.ts
@@ -24,6 +24,7 @@
 import {ChecksService} from './checks/checks-service';
 import {GrJsApiInterface} from '../elements/shared/gr-js-api-interface/gr-js-api-interface-element';
 import {GrStorageService} from './storage/gr-storage_impl';
+import {ConfigService} from './config/config-service';
 
 type ServiceName = keyof AppContext;
 type ServiceCreator<T> = () => T;
@@ -75,5 +76,6 @@
     checksService: () => new ChecksService(),
     jsApiService: () => new GrJsApiInterface(),
     storageService: () => new GrStorageService(),
+    configService: () => new ConfigService(),
   });
 }
diff --git a/polygerrit-ui/app/services/app-context.ts b/polygerrit-ui/app/services/app-context.ts
index cf186f0..fbc3115 100644
--- a/polygerrit-ui/app/services/app-context.ts
+++ b/polygerrit-ui/app/services/app-context.ts
@@ -23,6 +23,7 @@
 import {ChecksService} from './checks/checks-service';
 import {JsApiService} from '../elements/shared/gr-js-api-interface/gr-js-api-types';
 import {StorageService} from './storage/gr-storage';
+import {ConfigService} from './config/config-service';
 
 export interface AppContext {
   flagsService: FlagsService;
@@ -34,6 +35,7 @@
   checksService: ChecksService;
   jsApiService: JsApiService;
   storageService: StorageService;
+  configService: ConfigService;
 }
 
 /**
diff --git a/polygerrit-ui/app/services/change/change-model.ts b/polygerrit-ui/app/services/change/change-model.ts
index e7472de..7085d3c 100644
--- a/polygerrit-ui/app/services/change/change-model.ts
+++ b/polygerrit-ui/app/services/change/change-model.ts
@@ -87,6 +87,11 @@
   distinctUntilChanged()
 );
 
+export const repo$ = change$.pipe(
+  map(change => change?.project),
+  distinctUntilChanged()
+);
+
 export const latestPatchNum$ = change$.pipe(
   map(change => computeLatestPatchNum(computeAllPatchSets(change))),
   distinctUntilChanged()
@@ -104,8 +109,8 @@
   PatchSetNum | undefined
 > = changeAndRouterConsistent$.pipe(
   withLatestFrom(routerPatchNum$, latestPatchNum$),
-  map(([_, routerPatchNum, latestPatchNum]) => {
-    return routerPatchNum || latestPatchNum;
-  }),
+  map(
+    ([_, routerPatchNum, latestPatchNum]) => routerPatchNum || latestPatchNum
+  ),
   distinctUntilChanged()
 );
diff --git a/polygerrit-ui/app/services/checks/checks-model.ts b/polygerrit-ui/app/services/checks/checks-model.ts
index 4a532a0..e616bc2 100644
--- a/polygerrit-ui/app/services/checks/checks-model.ts
+++ b/polygerrit-ui/app/services/checks/checks-model.ts
@@ -27,13 +27,15 @@
 } from '../../api/checks';
 import {distinctUntilChanged, map} from 'rxjs/operators';
 import {PatchSetNumber} from '../../types/common';
+import {AttemptDetail, createAttemptMap} from './checks-util';
+import {assertIsDefined} from '../../utils/common-util';
 
 export interface CheckResult extends CheckResultApi {
   /**
    * Internally we want to uniquely identify a run with an id, for example when
    * efficiently re-rendering lists of runs in the UI.
    */
-  internalId: string;
+  internalResultId: string;
 }
 
 export interface CheckRun extends CheckRunApi {
@@ -41,7 +43,21 @@
    * Internally we want to uniquely identify a result with an id, for example
    * when efficiently re-rendering lists of results in the UI.
    */
-  internalId: string;
+  internalRunId: string;
+  /**
+   * Is this run attempt the latest attempt for the check, i.e. does it have
+   * the highest attempt number among all checks with the same name?
+   */
+  isLatestAttempt: boolean;
+  /**
+   * Is this the only attempt for the check, i.e. we don't have data for other
+   * attempts?
+   */
+  isSingleAttempt: boolean;
+  /**
+   * List of all attempts for the same check, ordered by attempt number.
+   */
+  attemptDetails: AttemptDetail[];
   results?: CheckResult[];
 }
 
@@ -90,49 +106,38 @@
 );
 
 export const someProvidersAreLoading$ = checksProviderState$.pipe(
-  map(state => {
-    return Object.values(state).some(providerState => providerState.loading);
-  }),
+  map(state =>
+    Object.values(state).some(providerState => providerState.loading)
+  ),
   distinctUntilChanged()
 );
 
 export const allActions$ = checksProviderState$.pipe(
-  map(state => {
-    return Object.values(state).reduce(
+  map(state =>
+    Object.values(state).reduce(
       (allActions: Action[], providerState: ChecksProviderState) => [
         ...allActions,
         ...providerState.actions,
       ],
       []
-    );
-  })
+    )
+  )
 );
 
 export const allRuns$ = checksProviderState$.pipe(
-  map(state => {
-    return Object.values(state).reduce(
+  map(state =>
+    Object.values(state).reduce(
       (allRuns: CheckRun[], providerState: ChecksProviderState) => [
         ...allRuns,
         ...providerState.runs,
       ],
       []
-    );
-  })
+    )
+  )
 );
 
-/** Array of check names that have at least 2 entries in allRuns$. */
-export const checksWithMultipleAttempts$ = allRuns$.pipe(
-  map(runs => {
-    const attemptsPerCheck = new Map<string, number>();
-    for (const run of runs) {
-      const check = run.checkName;
-      const attempts = attemptsPerCheck.get(check) ?? 0;
-      attemptsPerCheck.set(check, attempts + 1);
-    }
-    return [...attemptsPerCheck.keys()].filter(
-      check => (attemptsPerCheck.get(check) ?? 0) > 1
-    );
-  })
+export const allRunsLatest$ = allRuns$.pipe(
+  map(runs => runs.filter(run => run.isLatestAttempt))
 );
 
 export const checkToPluginMap$ = checksProviderState$.pipe(
@@ -148,8 +153,8 @@
 );
 
 export const allResults$ = checksProviderState$.pipe(
-  map(state => {
-    return Object.values(state)
+  map(state =>
+    Object.values(state)
       .reduce(
         (allResults: CheckResult[], providerState: ChecksProviderState) => [
           ...allResults,
@@ -161,8 +166,8 @@
         ],
         []
       )
-      .filter(r => r !== undefined);
-  })
+      .filter(r => r !== undefined)
+  )
 );
 
 // Must only be used by the checks service or whatever is in control of this
@@ -183,16 +188,20 @@
   privateState$.next(nextState);
 }
 
-// TODO(brohlfs): Remove all fake runs by end of January. They are just making
+// TODO(brohlfs): Remove all fake runs by end of April. They are just making
 // it easier to develop the UI and always see all the different types/states of
 // runs and results.
 
 export const fakeRun0: CheckRun = {
-  internalId: 'f0',
+  internalRunId: 'f0',
   checkName: 'FAKE Error Finder',
+  labelName: 'Presubmit',
+  isSingleAttempt: true,
+  isLatestAttempt: true,
+  attemptDetails: [],
   results: [
     {
-      internalId: 'f0r0',
+      internalResultId: 'f0r0',
       category: Category.ERROR,
       summary: 'I would like to point out this error: 1 is not equal to 2!',
       links: [
@@ -201,11 +210,36 @@
       tags: [{name: 'OBSOLETE'}, {name: 'E2E'}],
     },
     {
-      internalId: 'f0r1',
+      internalResultId: 'f0r1',
       category: Category.ERROR,
       summary: 'Running the mighty test has failed by crashing.',
+      actions: [
+        {
+          name: 'Ignore',
+          tooltip: 'Ignore this result',
+          primary: true,
+          callback: () => undefined,
+        },
+        {
+          name: 'Flag',
+          tooltip: 'Flag this result as not useful',
+          primary: true,
+          callback: () => undefined,
+        },
+        {
+          name: 'Upload',
+          tooltip: 'Upload the result to the super cloud.',
+          primary: false,
+          callback: () => undefined,
+        },
+      ],
+      tags: [{name: 'INTERRUPTED'}, {name: 'WINDOWS'}],
       links: [
-        {primary: true, url: 'https://www.google.com', icon: LinkIcon.EXTERNAL},
+        {primary: true, url: 'https://google.com', icon: LinkIcon.EXTERNAL},
+        {primary: true, url: 'https://google.com', icon: LinkIcon.DOWNLOAD},
+        {primary: true, url: 'https://google.com', icon: LinkIcon.REPORT_BUG},
+        {primary: true, url: 'https://google.com', icon: LinkIcon.HELP_PAGE},
+        {primary: true, url: 'https://google.com', icon: LinkIcon.HISTORY},
       ],
     },
   ],
@@ -213,31 +247,53 @@
 };
 
 export const fakeRun1: CheckRun = {
-  internalId: 'f1',
+  internalRunId: 'f1',
   checkName: 'FAKE Super Check',
   labelName: 'Verified',
+  isSingleAttempt: true,
+  isLatestAttempt: true,
+  attemptDetails: [],
   results: [
     {
-      internalId: 'f1r0',
+      internalResultId: 'f1r0',
       category: Category.WARNING,
       summary: 'We think that you could improve this.',
       message: `There is a lot to be said. A lot. I say, a lot.\n
                 So please keep reading.`,
       tags: [{name: 'INTERRUPTED'}, {name: 'WINDOWS'}],
+      links: [
+        {primary: true, url: 'https://google.com', icon: LinkIcon.EXTERNAL},
+        {primary: true, url: 'https://google.com', icon: LinkIcon.DOWNLOAD},
+        {
+          primary: true,
+          url: 'https://google.com',
+          icon: LinkIcon.DOWNLOAD_MOBILE,
+        },
+        {primary: true, url: 'https://google.com', icon: LinkIcon.IMAGE},
+      ],
     },
   ],
   status: RunStatus.RUNNING,
 };
 
 export const fakeRun2: CheckRun = {
-  internalId: 'f2',
+  internalRunId: 'f2',
   checkName: 'FAKE Mega Analysis',
+  isSingleAttempt: true,
+  isLatestAttempt: true,
+  attemptDetails: [],
   results: [
     {
-      internalId: 'f2r0',
+      internalResultId: 'f2r0',
       category: Category.INFO,
       summary: 'This is looking a bit too large.',
-      message: 'We are still looking into how large exactly. Stay tuned.',
+      message: `We are still looking into how large exactly. Stay tuned.
+And have a look at https://www.google.com!
+
+Or have a look at change 30000.
+Example code:
+  const constable = '';
+  var variable = '';`,
       tags: [{name: 'FLAKY'}, {name: 'MAC-OS'}],
     },
   ],
@@ -245,15 +301,73 @@
 };
 
 export const fakeRun3: CheckRun = {
-  internalId: 'f3',
+  internalRunId: 'f3',
   checkName: 'FAKE Critical Observations',
   status: RunStatus.RUNNABLE,
+  isSingleAttempt: true,
+  isLatestAttempt: true,
+  attemptDetails: [],
 };
 
-export const fakeRun4: CheckRun = {
-  internalId: 'f4',
-  checkName: 'FAKE TODO Elimination',
+export const fakeRun4_1: CheckRun = {
+  internalRunId: 'f4',
+  checkName: 'FAKE Elimination',
   status: RunStatus.COMPLETED,
+  attempt: 1,
+  isSingleAttempt: false,
+  isLatestAttempt: false,
+  attemptDetails: [],
+};
+
+export const fakeRun4_2: CheckRun = {
+  internalRunId: 'f4',
+  checkName: 'FAKE Elimination',
+  status: RunStatus.COMPLETED,
+  attempt: 2,
+  isSingleAttempt: false,
+  isLatestAttempt: false,
+  attemptDetails: [],
+  results: [
+    {
+      internalResultId: 'f42r0',
+      category: Category.INFO,
+      summary: 'Please eliminate all the TODOs!',
+    },
+  ],
+};
+
+export const fakeRun4_3: CheckRun = {
+  internalRunId: 'f4',
+  checkName: 'FAKE Elimination',
+  status: RunStatus.COMPLETED,
+  attempt: 3,
+  isSingleAttempt: false,
+  isLatestAttempt: false,
+  attemptDetails: [],
+  results: [
+    {
+      internalResultId: 'f43r0',
+      category: Category.ERROR,
+      summary: 'Without eliminating all the TODOs your change will break!',
+    },
+  ],
+};
+
+export const fakeRun4_4: CheckRun = {
+  internalRunId: 'f4',
+  checkName: 'FAKE Elimination',
+  status: RunStatus.RUNNING,
+  attempt: 4,
+  isSingleAttempt: false,
+  isLatestAttempt: true,
+  attemptDetails: [],
+  results: [
+    {
+      internalResultId: 'f44r0',
+      category: Category.INFO,
+      summary: 'Dont be afraid. All TODOs will be eliminated.',
+    },
+  ],
 };
 
 export const fakeActions: Action[] = [
@@ -301,6 +415,12 @@
   runs: CheckRunApi[],
   actions: Action[] = []
 ) {
+  const attemptMap = createAttemptMap(runs);
+  for (const attemptInfo of attemptMap.values()) {
+    // Per run only one attempt can be undefined, so the '?? -1' is not really
+    // relevant for sorting.
+    attemptInfo.attempts.sort((a, b) => (b.attempt ?? -1) - (a.attempt ?? -1));
+  }
   const nextState = {...privateState$.getValue()};
   nextState.providerNameToState = {...nextState.providerNameToState};
   nextState.providerNameToState[pluginName] = {
@@ -308,13 +428,18 @@
     loading: false,
     runs: runs.map(run => {
       const runId = `${run.checkName}-${run.change}-${run.patchset}-${run.attempt}`;
+      const attemptInfo = attemptMap.get(run.checkName);
+      assertIsDefined(attemptInfo, 'attemptInfo');
       return {
         ...run,
-        internalId: runId,
+        internalRunId: runId,
+        isLatestAttempt: attemptInfo.latestAttempt === run.attempt,
+        isSingleAttempt: attemptInfo.isSingleAttempt,
+        attemptDetails: attemptInfo.attempts,
         results: (run.results ?? []).map((result, i) => {
           return {
             ...result,
-            internalId: `${runId}-${i}`,
+            internalResultId: `${runId}-${i}`,
           };
         }),
       };
diff --git a/polygerrit-ui/app/services/checks/checks-util.ts b/polygerrit-ui/app/services/checks/checks-util.ts
index 5e5b869..339d0bf 100644
--- a/polygerrit-ui/app/services/checks/checks-util.ts
+++ b/polygerrit-ui/app/services/checks/checks-util.ts
@@ -14,10 +14,59 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import {Action, Category, RunStatus} from '../../api/checks';
+import {
+  Action,
+  Category,
+  CheckRun as CheckRunApi,
+  CheckResult as CheckResultApi,
+  LinkIcon,
+  RunStatus,
+} from '../../api/checks';
 import {assertNever} from '../../utils/common-util';
 import {CheckResult, CheckRun} from './checks-model';
 
+export function iconForLink(linkIcon: LinkIcon) {
+  switch (linkIcon) {
+    case LinkIcon.EXTERNAL:
+      return 'launch';
+    case LinkIcon.IMAGE:
+      return 'insert-photo';
+    case LinkIcon.HISTORY:
+      return 'restore';
+    case LinkIcon.DOWNLOAD:
+      return 'download';
+    case LinkIcon.DOWNLOAD_MOBILE:
+      return 'system-update';
+    case LinkIcon.HELP_PAGE:
+      return 'help-outline';
+    case LinkIcon.REPORT_BUG:
+      return 'bug';
+    default:
+      assertNever(linkIcon, `Unsupported LinkIcon: ${linkIcon}`);
+  }
+}
+
+export function tooltipForLink(linkIcon: LinkIcon) {
+  switch (linkIcon) {
+    case LinkIcon.EXTERNAL:
+      return 'Link to details';
+    case LinkIcon.IMAGE:
+      return 'Link to image';
+    case LinkIcon.HISTORY:
+      return 'Link to result history';
+    case LinkIcon.DOWNLOAD:
+      return 'Download';
+    case LinkIcon.DOWNLOAD_MOBILE:
+      return 'Download';
+    case LinkIcon.HELP_PAGE:
+      return 'Link to help page';
+    case LinkIcon.REPORT_BUG:
+      return 'Link for reporting a problem';
+    default:
+      assertNever(linkIcon, `Unsupported LinkIcon: ${linkIcon}`);
+  }
+}
+
 export function worstCategory(run: CheckRun) {
   if (hasResultsOf(run, Category.ERROR)) return Category.ERROR;
   if (hasResultsOf(run, Category.WARNING)) return Category.WARNING;
@@ -124,9 +173,13 @@
 }
 
 export function allResults(runs: CheckRun[]): CheckResult[] {
-  return runs.reduce((results: CheckResult[], run: CheckRun) => {
-    return [...results, ...(run.results ?? [])];
-  }, []);
+  return runs.reduce(
+    (results: CheckResult[], run: CheckRun) => [
+      ...results,
+      ...(run.results ?? []),
+    ],
+    []
+  );
 }
 
 export function hasResultsOf(run: CheckRun, category: Category) {
@@ -179,3 +232,63 @@
     })
   );
 }
+
+export interface AttemptDetail {
+  attempt: number | undefined;
+  icon: string;
+}
+
+export interface AttemptInfo {
+  latestAttempt: number | undefined;
+  isSingleAttempt: boolean;
+  attempts: AttemptDetail[];
+}
+
+export function createAttemptMap(runs: CheckRunApi[]) {
+  const map = new Map<string, AttemptInfo>();
+  for (const run of runs) {
+    const value = map.get(run.checkName);
+    const detail = {
+      attempt: run.attempt,
+      icon: iconForRun(fromApiToInternalRun(run)),
+    };
+    if (value === undefined) {
+      map.set(run.checkName, {
+        latestAttempt: run.attempt,
+        isSingleAttempt: true,
+        attempts: [detail],
+      });
+      continue;
+    }
+    if (!run.attempt || !value.latestAttempt) {
+      throw new Error(
+        'If multiple run attempts are provided, ' +
+          'then each run must have the "attempt" property set.'
+      );
+    }
+    value.isSingleAttempt = false;
+    if (run.attempt > value.latestAttempt) {
+      value.latestAttempt = run.attempt;
+    }
+    value.attempts.push(detail);
+  }
+  return map;
+}
+
+export function fromApiToInternalRun(run: CheckRunApi): CheckRun {
+  return {
+    ...run,
+    internalRunId: 'fake',
+    isSingleAttempt: false,
+    isLatestAttempt: false,
+    attemptDetails: [],
+    results: (run.results ?? []).map(fromApiToInternalResult),
+  };
+}
+
+export function fromApiToInternalResult(result: CheckResultApi): CheckResult {
+  return {
+    ...result,
+    internalResultId: 'fake',
+  };
+}
diff --git a/polygerrit-ui/app/services/config/config-model.ts b/polygerrit-ui/app/services/config/config-model.ts
new file mode 100644
index 0000000..254760b
--- /dev/null
+++ b/polygerrit-ui/app/services/config/config-model.ts
@@ -0,0 +1,44 @@
+/**
+ * @license
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import {ConfigInfo} from '../../types/common';
+import {BehaviorSubject, Observable} from 'rxjs';
+import {map, distinctUntilChanged} from 'rxjs/operators';
+
+interface ConfigState {
+  repoConfig?: ConfigInfo;
+}
+
+// TODO: Figure out how to best enforce immutability of all states. Use Immer?
+// Use DeepReadOnly?
+const initialState: ConfigState = {};
+
+const privateState$ = new BehaviorSubject(initialState);
+
+// Re-exporting as Observable so that you can only subscribe, but not emit.
+export const configState$: Observable<ConfigState> = privateState$;
+
+// Must only be used by the change service or whatever is in control of this
+// model.
+export function updateRepoConfig(repoConfig?: ConfigInfo) {
+  const current = privateState$.getValue();
+  privateState$.next({...current, repoConfig});
+}
+
+export const repoConfig$ = configState$.pipe(
+  map(configState => configState.repoConfig),
+  distinctUntilChanged()
+);
diff --git a/polygerrit-ui/app/services/config/config-service.ts b/polygerrit-ui/app/services/config/config-service.ts
new file mode 100644
index 0000000..d6ff99c
--- /dev/null
+++ b/polygerrit-ui/app/services/config/config-service.ts
@@ -0,0 +1,39 @@
+/**
+ * @license
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import {updateRepoConfig} from './config-model';
+import {repo$} from '../change/change-model';
+import {appContext} from '../app-context';
+import {switchMap} from 'rxjs/operators';
+import {ConfigInfo, RepoName} from '../../types/common';
+import {from, of} from 'rxjs';
+
+export class ConfigService {
+  private readonly restApiService = appContext.restApiService;
+
+  constructor() {
+    repo$
+      .pipe(
+        switchMap((repo?: RepoName) => {
+          if (repo === undefined) return of(undefined);
+          return from(this.restApiService.getProjectConfig(repo));
+        })
+      )
+      .subscribe((repoConfig?: ConfigInfo) => {
+        updateRepoConfig(repoConfig);
+      });
+  }
+}
diff --git a/polygerrit-ui/app/services/flags/flags.ts b/polygerrit-ui/app/services/flags/flags.ts
index ff950b8..6f94b8d 100644
--- a/polygerrit-ui/app/services/flags/flags.ts
+++ b/polygerrit-ui/app/services/flags/flags.ts
@@ -31,4 +31,5 @@
   NEW_CHANGE_SUMMARY_UI = 'UiFeature__new_change_summary_ui',
   NEW_IMAGE_DIFF_UI = 'UiFeature__new_image_diff_ui',
   COMMENT_CONTEXT = 'UiFeature__comment_context',
+  TOKEN_HIGHLIGHTING = 'UiFeature__token_highlighting',
 }
diff --git a/polygerrit-ui/app/services/gr-reporting/gr-reporting_impl.ts b/polygerrit-ui/app/services/gr-reporting/gr-reporting_impl.ts
index e8dfd3f..5fd4234 100644
--- a/polygerrit-ui/app/services/gr-reporting/gr-reporting_impl.ts
+++ b/polygerrit-ui/app/services/gr-reporting/gr-reporting_impl.ts
@@ -141,9 +141,7 @@
       lineno?: number,
       colno?: number,
       error?: Error
-    ) => {
-      return onError(oldOnError, event, source, lineno, colno, error);
-    };
+    ) => onError(oldOnError, event, source, lineno, colno, error);
     context.addEventListener(
       'unhandledrejection',
       (e: PromiseRejectionEvent) => {
diff --git a/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock.ts b/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock.ts
index c4030c9..c180439 100644
--- a/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock.ts
+++ b/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock.ts
@@ -47,9 +47,7 @@
   diffViewDisplayed: () => {},
   diffViewFullyLoaded: () => {},
   fileListDisplayed: () => {},
-  getTimer: () => {
-    return new MockTimer();
-  },
+  getTimer: () => new MockTimer(),
   locationChanged: (page: string) => {
     log(`locationChanged: ${page}`);
   },
diff --git a/polygerrit-ui/app/services/storage/gr-storage_mock.ts b/polygerrit-ui/app/services/storage/gr-storage_mock.ts
index bfffe32..399ffe4 100644
--- a/polygerrit-ui/app/services/storage/gr-storage_mock.ts
+++ b/polygerrit-ui/app/services/storage/gr-storage_mock.ts
@@ -38,9 +38,7 @@
   return key;
 };
 
-const getEditableContentKey = (key: string): string => {
-  return `editablecontent:${key}`;
-};
+const getEditableContentKey = (key: string): string => `editablecontent:${key}`;
 
 export function cleanUpStorage() {
   storage.clear();
diff --git a/polygerrit-ui/app/styles/shared-styles.ts b/polygerrit-ui/app/styles/shared-styles.ts
index 6d128b3..2af1e46 100644
--- a/polygerrit-ui/app/styles/shared-styles.ts
+++ b/polygerrit-ui/app/styles/shared-styles.ts
@@ -239,16 +239,19 @@
       font-family: var(--header-font-family);
       -webkit-font-smoothing: initial;
     }
-    --paper-tab-content-focused: {
-      /* paper-tabs uses 700 here, which can look awkward */
-      font-weight: var(--font-weight-h3);
-    }
     --paper-tab-content-unselected: {
       /* paper-tabs uses 0.8 here, but we want to control the color directly */
       opacity: 1;
       color: var(--deemphasized-text-color);
     }
   }
+  paper-tab {
+    --paper-tab-content-focused: {
+      /* paper-tabs uses 700 here, which can look awkward */
+      font-weight: var(--font-weight-h3);
+      outline: auto;
+    }
+  }
   iron-autogrow-textarea {
     /** This is needed for firefox */
     --iron-autogrow-textarea_-_white-space: pre-wrap;
diff --git a/polygerrit-ui/app/styles/themes/app-theme.ts b/polygerrit-ui/app/styles/themes/app-theme.ts
index 838d82b..d768c96 100644
--- a/polygerrit-ui/app/styles/themes/app-theme.ts
+++ b/polygerrit-ui/app/styles/themes/app-theme.ts
@@ -253,6 +253,7 @@
     --status-wip: #795548;
     --status-private: var(--purple-500);
     --status-conflict: var(--red-600);
+    --status-revert-created: #e64a19;
     --status-active: var(--blue-700);
     --status-ready: var(--pink-800);
     --status-custom: var(--purple-900);
@@ -336,6 +337,7 @@
     --coverage-covered: #e0f2f1;
     --coverage-not-covered: #ffd1a4;
     --ranged-comment-hint-text-color: var(--orange-900);
+    --token-highlighting-color: #fffd54;
 
     /* syntax colors */
     --syntax-attr-color: #219;
diff --git a/polygerrit-ui/app/styles/themes/dark-theme.ts b/polygerrit-ui/app/styles/themes/dark-theme.ts
index 4b824b2..dec438d 100644
--- a/polygerrit-ui/app/styles/themes/dark-theme.ts
+++ b/polygerrit-ui/app/styles/themes/dark-theme.ts
@@ -151,6 +151,7 @@
       --status-wip: #bcaaa4;
       --status-private: var(--purple-200);
       --status-conflict: var(--red-300);
+      --status-revert-created: #ff8a65;
       --status-active: var(--blue-400);
       --status-ready: var(--pink-500);
       --status-custom: var(--purple-400);
@@ -198,6 +199,7 @@
       --coverage-covered: #112826;
       --coverage-not-covered: #6b3600;
       --ranged-comment-hint-text-color: var(--blue-50);
+      --token-highlighting-color: var(--yellow-tonal);
 
       /* syntax colors */
       --syntax-attr-color: #80cbbf;
diff --git a/polygerrit-ui/app/types/common.ts b/polygerrit-ui/app/types/common.ts
index c628661..0f229df 100644
--- a/polygerrit-ui/app/types/common.ts
+++ b/polygerrit-ui/app/types/common.ts
@@ -1766,6 +1766,7 @@
   email_strategy: EmailStrategy;
   default_base_for_merges: DefaultBase;
   publish_comments_on_push?: boolean;
+  disable_keyboard_shortcuts?: boolean;
   work_in_progress_by_default?: boolean;
   // The email_format doesn't mentioned in doc, but exists in Java class GeneralPreferencesInfo
   email_format?: EmailFormat;
diff --git a/polygerrit-ui/app/types/events.ts b/polygerrit-ui/app/types/events.ts
index 7bde788..ff08c57 100644
--- a/polygerrit-ui/app/types/events.ts
+++ b/polygerrit-ui/app/types/events.ts
@@ -84,9 +84,7 @@
 export interface ChangeMessageDeletedEventDetail {
   message: ChangeMessage;
 }
-export type ChangeMessageDeletedEvent = CustomEvent<
-  ChangeMessageDeletedEventDetail
->;
+export type ChangeMessageDeletedEvent = CustomEvent<ChangeMessageDeletedEventDetail>;
 
 // TODO(milutin) - remove once new gr-dialog will do it out of the box
 // This informs gr-app-element to remove footer, header from a11y tree
@@ -99,9 +97,7 @@
 export interface EditableContentSaveEventDetail {
   content: string;
 }
-export type EditableContentSaveEvent = CustomEvent<
-  EditableContentSaveEventDetail
->;
+export type EditableContentSaveEvent = CustomEvent<EditableContentSaveEventDetail>;
 
 export interface RpcLogEventDetail {
   status: number | null;
diff --git a/polygerrit-ui/app/utils/change-metadata-util.ts b/polygerrit-ui/app/utils/change-metadata-util.ts
index eda988a..9692ab3 100644
--- a/polygerrit-ui/app/utils/change-metadata-util.ts
+++ b/polygerrit-ui/app/utils/change-metadata-util.ts
@@ -24,6 +24,7 @@
   SUBMITTED = 'Submitted',
   PARENT = 'Parent',
   MERGED_AS = 'Merged as',
+  REVERT_CREATED_AS = 'Revert Created as',
   STRATEGY = 'Strategy',
   UPDATED = 'Updated',
   CC = 'CC',
@@ -56,6 +57,7 @@
   ALWAYS_HIDE: [
     Metadata.PARENT,
     Metadata.MERGED_AS,
+    Metadata.REVERT_CREATED_AS,
     Metadata.STRATEGY,
     Metadata.UPDATED,
   ],
diff --git a/polygerrit-ui/app/utils/change-util.ts b/polygerrit-ui/app/utils/change-util.ts
index d7fb5d0..b2d23a0 100644
--- a/polygerrit-ui/app/utils/change-util.ts
+++ b/polygerrit-ui/app/utils/change-util.ts
@@ -24,6 +24,7 @@
   RelatedChangeAndCommitInfo,
 } from '../types/common';
 import {ParsedChangeInfo} from '../types/types';
+import {isRevertCreated} from './message-util';
 
 // This can be wrong! See WARNING above
 interface ChangeStatusesOptions {
@@ -134,6 +135,7 @@
   return change?.status === ChangeStatus.NEW;
 }
 
+// TODO(TS): use enum ChangeStates in gr-change-status
 export function changeStatuses(
   change: ChangeInfo,
   opt_options?: ChangeStatusesOptions
@@ -156,6 +158,9 @@
   if (change.is_private) {
     states.push('Private');
   }
+  if (isRevertCreated(change.messages)) {
+    states.push('Revert Created');
+  }
 
   // If there are any pre-defined statuses, only return those. Otherwise,
   // will determine the derived status.
diff --git a/polygerrit-ui/app/utils/dom-util.ts b/polygerrit-ui/app/utils/dom-util.ts
index 3affef7..4f83881 100644
--- a/polygerrit-ui/app/utils/dom-util.ts
+++ b/polygerrit-ui/app/utils/dom-util.ts
@@ -15,8 +15,9 @@
  * limitations under the License.
  */
 
-import {EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
+import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
 import {check} from './common-util';
+import {CustomKeyboardEvent} from '../types/events';
 
 /**
  * Event emitted from polymer elements.
@@ -292,3 +293,23 @@
     el.classList.remove(className);
   }
 }
+
+export function isModifierPressed(event: CustomKeyboardEvent) {
+  const e = getKeyboardEvent(event);
+  return e.altKey || e.ctrlKey || e.metaKey || e.shiftKey;
+}
+
+export function isShiftPressed(event: CustomKeyboardEvent) {
+  const e = getKeyboardEvent(event);
+  return e.shiftKey;
+}
+
+export function getKeyboardEvent(e: CustomKeyboardEvent): CustomKeyboardEvent {
+  const event = dom(e.detail ? e.detail.keyboardEvent : e);
+  // TODO(TS): worth checking if this still holds or not, if no, remove this.
+  // When e is a keyboardEvent, e.event is not null.
+  if ('event' in event && (event as CustomKeyboardEvent).event) {
+    return (event as CustomKeyboardEvent).event;
+  }
+  return event as CustomKeyboardEvent;
+}
diff --git a/polygerrit-ui/app/utils/message-util.ts b/polygerrit-ui/app/utils/message-util.ts
new file mode 100644
index 0000000..f2d7e6b
--- /dev/null
+++ b/polygerrit-ui/app/utils/message-util.ts
@@ -0,0 +1,32 @@
+/**
+ * @license
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {MessageTag} from '../constants/constants';
+import {ChangeMessageInfo} from '../types/common';
+
+export function getRevertCommitHash(messages?: ChangeMessageInfo[]) {
+  const msg = messages?.find(m => m.tag === MessageTag.TAG_REVERT);
+  if (!msg) return undefined;
+  const REVERT_REGEX = /^Created a revert of this change as (.*)$/;
+  const commit = msg.message.match(REVERT_REGEX)?.[1];
+  if (!commit) throw new Error('revert commit not found');
+  return commit;
+}
+
+export function isRevertCreated(messages?: ChangeMessageInfo[]) {
+  return messages?.some(m => m.tag === MessageTag.TAG_REVERT);
+}
diff --git a/polygerrit-ui/app/yarn.lock b/polygerrit-ui/app/yarn.lock
index deddbad..77d3972 100644
--- a/polygerrit-ui/app/yarn.lock
+++ b/polygerrit-ui/app/yarn.lock
@@ -19,7 +19,7 @@
   resolved "https://registry.yarnpkg.com/@polymer/font-roboto/-/font-roboto-3.0.2.tgz#80cdaa7225db2359130dfb2c6d9a3be1820020c3"
   integrity sha512-tx5TauYSmzsIvmSqepUPDYbs4/Ejz2XbZ1IkD7JEGqkdNUJlh+9KU85G56Tfdk/xjEZ8zorFfN09OSwiMrIQWA==
 
-"@polymer/iron-a11y-announcer@^3.0.0-pre.26", "@polymer/iron-a11y-announcer@^3.0.1":
+"@polymer/iron-a11y-announcer@^3.0.0-pre.26", "@polymer/iron-a11y-announcer@^3.1.0":
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/@polymer/iron-a11y-announcer/-/iron-a11y-announcer-3.1.0.tgz#3d3712a165070ed3cdfc39e54f95515c913c9613"
   integrity sha512-lc5i4NKB8kSQHH0Hwu8WS3ym93m+J69OHJWSSBxwd17FI+h2wmgxDzeG9LI4ojMMck17/uc2pLe7g/UHt5/K/A==
@@ -70,10 +70,10 @@
     "@polymer/neon-animation" "^3.0.0-pre.26"
     "@polymer/polymer" "^3.0.0"
 
-"@polymer/iron-fit-behavior@^3.0.0-pre.26", "@polymer/iron-fit-behavior@^3.0.2":
-  version "3.0.2"
-  resolved "https://registry.yarnpkg.com/@polymer/iron-fit-behavior/-/iron-fit-behavior-3.0.2.tgz#2ec460d8a6b0151394b55631a72a68b92e14e2e0"
-  integrity sha512-JndryJYbBR3gSN5IlST4rCHsd01+OyvYpRO6z5Zd3C6u5V/m07TwAtcf3aXwZ8WBNt2eLG28OcvdSO7XR2v2pg==
+"@polymer/iron-fit-behavior@^3.0.0-pre.26", "@polymer/iron-fit-behavior@^3.1.0":
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/@polymer/iron-fit-behavior/-/iron-fit-behavior-3.1.0.tgz#8197a61e0ce2234e9bf8fbd7a1ae53d1a06026b0"
+  integrity sha512-ABcgIYqrjhmUT8tiuolqeGttF/8pd3sEymUDrO1vXbZu4FWIvoLNndrMDFvs++AGd12Mjf5pYy84NJc6dB8Vig==
   dependencies:
     "@polymer/polymer" "^3.0.0"
 
@@ -212,10 +212,10 @@
     "@polymer/paper-styles" "^3.0.0-pre.26"
     "@polymer/polymer" "^3.0.0"
 
-"@polymer/paper-checkbox@3.0.1":
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/@polymer/paper-checkbox/-/paper-checkbox-3.0.1.tgz#4dead448e853885dc2f4fc6a2c92f1768c9d2103"
-  integrity sha512-uliJWKTgE1NN+80qZpzygfbQh5SfTVyBKOs3tyyTHFVJNNkMaZGn2fJghg3Jb//KNqYueBLwRLxe3FPbey+91g==
+"@polymer/paper-checkbox@^3.1.0":
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/@polymer/paper-checkbox/-/paper-checkbox-3.1.0.tgz#66b903ae5814db237d027deb4a3f3430f48d905b"
+  integrity sha512-kXm6yDG1tT8if0XuJ2cc9NF+g8Ev4wG+rnf0a+Sx+O7J6fn1jcnBlYn72FlrfjVjDQZDBFmT6nynhD5PvFw8iQ==
   dependencies:
     "@polymer/iron-a11y-keys-behavior" "^3.0.0-pre.26"
     "@polymer/iron-checked-element-behavior" "^3.0.0-pre.26"
@@ -253,10 +253,10 @@
     "@polymer/paper-dialog-behavior" "^3.0.0-pre.26"
     "@polymer/polymer" "^3.0.0"
 
-"@polymer/paper-dropdown-menu@3.0.1":
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/@polymer/paper-dropdown-menu/-/paper-dropdown-menu-3.0.1.tgz#73d7b962de2ccd52bc644b42a7e3f5de4cb99c2f"
-  integrity sha512-GBFzoP8SC+MTcLgKAflmGEvfjboCFVNkJd39fBEoNHAV3KU92ugmR4sl9iFaIaaGuxJ7QdjsLa2zQPlcS4lr6Q==
+"@polymer/paper-dropdown-menu@^3.2.0":
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/@polymer/paper-dropdown-menu/-/paper-dropdown-menu-3.2.0.tgz#17f507ef864dc18365a92e256bde628c2d352956"
+  integrity sha512-2ohwSHF+RLSK6kA0UkkMiMQF6EZcaEYWAA25kfisI6DWie7yozKrpQNsqvwfOEHU6DdDMIotrOtH1TM88YS8Zg==
   dependencies:
     "@polymer/iron-a11y-keys-behavior" "^3.0.0-pre.26"
     "@polymer/iron-form-element-behavior" "^3.0.0-pre.26"
@@ -264,11 +264,11 @@
     "@polymer/iron-iconset-svg" "^3.0.0-pre.26"
     "@polymer/iron-validatable-behavior" "^3.0.0-pre.26"
     "@polymer/paper-behaviors" "^3.0.0-pre.27"
-    "@polymer/paper-input" "^3.0.0-pre.26"
-    "@polymer/paper-menu-button" "^3.0.0-pre.26"
+    "@polymer/paper-input" "^3.1.0"
+    "@polymer/paper-menu-button" "^3.1.0"
     "@polymer/paper-ripple" "^3.0.0-pre.26"
     "@polymer/paper-styles" "^3.0.0-pre.26"
-    "@polymer/polymer" "^3.0.0"
+    "@polymer/polymer" "^3.3.1"
 
 "@polymer/paper-icon-button@^3.0.0-pre.26":
   version "3.0.2"
@@ -280,7 +280,7 @@
     "@polymer/paper-styles" "^3.0.0-pre.26"
     "@polymer/polymer" "^3.0.0"
 
-"@polymer/paper-input@^3.0.0-pre.26", "@polymer/paper-input@^3.2.1":
+"@polymer/paper-input@^3.1.0", "@polymer/paper-input@^3.2.1":
   version "3.2.1"
   resolved "https://registry.yarnpkg.com/@polymer/paper-input/-/paper-input-3.2.1.tgz#0fd0d30de3b43ba7d2c8d5d76f870d257b667ebf"
   integrity sha512-6ghgwQKM6mS0hAQxQqj+tkeEY1VUBqAsrasAm8V5RpNcfSWQC/hhRFxU0beGuKTAhndzezDzWYP6Zz4b8fExGg==
@@ -313,15 +313,15 @@
     "@polymer/paper-styles" "^3.0.0-pre.26"
     "@polymer/polymer" "^3.0.0"
 
-"@polymer/paper-menu-button@^3.0.0-pre.26":
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/@polymer/paper-menu-button/-/paper-menu-button-3.0.1.tgz#318fc4d884a01d42ed0f3f3b5a6f78548d64befa"
-  integrity sha512-Rxte2Fp7N2BMI2FMM7tB25IkvD11DhjMklcg97JP1jnlHbJNrXPh5SSX2bdtabz49UE8vejIsrxZ+AGsB5nqIQ==
+"@polymer/paper-menu-button@^3.1.0":
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/@polymer/paper-menu-button/-/paper-menu-button-3.1.0.tgz#3eb2fb88ba3cdaa4c39be6ae3530efa40b1eccf3"
+  integrity sha512-q0G0/rvYD/FFmIBMGCQWjfXzRqwFw9+WHSYV4uOQzM1Ln8LMXSAd+2CENsbVwtMh6fmBePj15ZlU8SM2dt1WDQ==
   dependencies:
     "@polymer/iron-a11y-keys-behavior" "^3.0.0-pre.26"
     "@polymer/iron-behaviors" "^3.0.0-pre.26"
     "@polymer/iron-dropdown" "^3.0.0-pre.26"
-    "@polymer/iron-fit-behavior" "^3.0.0-pre.26"
+    "@polymer/iron-fit-behavior" "^3.1.0"
     "@polymer/neon-animation" "^3.0.0-pre.26"
     "@polymer/paper-styles" "^3.0.0-pre.26"
     "@polymer/polymer" "^3.0.0"
@@ -377,29 +377,22 @@
     "@polymer/paper-styles" "^3.0.0-pre.26"
     "@polymer/polymer" "^3.0.0"
 
-"@polymer/polymer@^3.0.0", "@polymer/polymer@^3.0.5", "@polymer/polymer@^3.4.1":
+"@polymer/polymer@^3.0.0", "@polymer/polymer@^3.0.2", "@polymer/polymer@^3.0.5", "@polymer/polymer@^3.3.1", "@polymer/polymer@^3.4.1":
   version "3.4.1"
   resolved "https://registry.yarnpkg.com/@polymer/polymer/-/polymer-3.4.1.tgz#333bef25711f8411bb5624fb3eba8212ef8bee96"
   integrity sha512-KPWnhDZibtqKrUz7enIPOiO4ZQoJNOuLwqrhV2MXzIt3VVnUVJVG5ORz4Z2sgO+UZ+/UZnPD0jqY+jmw/+a9mQ==
   dependencies:
     "@webcomponents/shadycss" "^1.9.1"
 
-"@polymer/polymer@^3.0.2":
-  version "3.3.1"
-  resolved "https://registry.yarnpkg.com/@polymer/polymer/-/polymer-3.3.1.tgz#9ad48992d2a96775f80b0673f3a615d6df8a3dfc"
-  integrity sha512-8KaB48tzyMjdsHdxo5KvCAaqmTe7rYDzQAoj/pyEfq9Fp4YfUaS+/xqwYj0GbiDAUNzwkmEQ7dw9cgnRNdKO8A==
-  dependencies:
-    "@webcomponents/shadycss" "^1.9.1"
-
 "@types/resize-observer-browser@^0.1.5":
   version "0.1.5"
   resolved "https://registry.yarnpkg.com/@types/resize-observer-browser/-/resize-observer-browser-0.1.5.tgz#36d897708172ac2380cd486da7a3daf1161c1e23"
   integrity sha512-8k/67Z95Goa6Lznuykxkfhq9YU3l1Qe6LNZmwde1u7802a3x8v44oq0j91DICclxatTr0rNnhXx7+VTIetSrSQ==
 
-"@webcomponents/shadycss@^1.9.1", "@webcomponents/shadycss@^1.9.2":
-  version "1.9.4"
-  resolved "https://registry.yarnpkg.com/@webcomponents/shadycss/-/shadycss-1.9.4.tgz#4f9d8ea1526bab084c60b53d4854dc39fdb2bb48"
-  integrity sha512-tgNcVEaKssyeZPbUBjVQf4aryO5Fi7fxRvOxV982ZJuRVDcefmIblBh0SXAbcvAAlQ2zpNEP4SuQUnr8uApIpw==
+"@webcomponents/shadycss@^1.10.2", "@webcomponents/shadycss@^1.9.1":
+  version "1.10.2"
+  resolved "https://registry.yarnpkg.com/@webcomponents/shadycss/-/shadycss-1.10.2.tgz#40e03cab6dc5e12f199949ba2b79e02f183d1e7b"
+  integrity sha512-9Iseu8bRtecb0klvv+WXZOVZatsRkbaH7M97Z+f+Pt909R4lDfgUODAnra23DOZTpeMTAkVpf4m/FZztN7Ox1A==
 
 "@webcomponents/webcomponentsjs@^1.3.3":
   version "1.3.3"
@@ -407,9 +400,9 @@
   integrity sha512-eLH04VBMpuZGzBIhOnUjECcQPEPcmfhWEijW9u1B5I+2PPYdWf3vWUExdDxu4Y3GljRSTCOlWnGtS9tpzmXMyQ==
 
 "@webcomponents/webcomponentsjs@^2.0.3":
-  version "2.4.1"
-  resolved "https://registry.yarnpkg.com/@webcomponents/webcomponentsjs/-/webcomponentsjs-2.4.1.tgz#7baadec56ed2fd79b94ddfd509132d8c0c295c5c"
-  integrity sha512-7jxBb+KoWncKb/JGFyTY40PjV4yRx2zd35ZLuvRP+6WndJDL7X32ZIZ7bN3sSQIl+NzJkCo7chfXJyzn+6WZaQ==
+  version "2.5.0"
+  resolved "https://registry.yarnpkg.com/@webcomponents/webcomponentsjs/-/webcomponentsjs-2.5.0.tgz#61b27785a6ad5bfd68fa018201fe418b118cb38d"
+  integrity sha512-C0l51MWQZ9kLzcxOZtniOMohpIFdCLZum7/TEHv3XWFc1Fvt5HCpbSX84x8ltka/JuNKcuiDnxXFkiB2gaePcg==
 
 "ba-linkify@file:../../lib/ba-linkify/src":
   version "1.0.0"
@@ -431,10 +424,10 @@
   resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-1.3.0.tgz#c80f3cc5793a6dea6c07172be90a70ab20e56034"
   integrity sha512-0Q1bwmaFH9O14vycPHw8C/IeHMk/uSDldVLIefu/kfbTBGIc44KGH6A8p1bDfxUfHdc8q6Ct7kQklWoHgr4t1Q==
 
-page@^1.11.5:
-  version "1.11.5"
-  resolved "https://registry.yarnpkg.com/page/-/page-1.11.5.tgz#0cfc8608be337f26f4377f31df0787aef0ca1af7"
-  integrity sha512-0JXUHc7Y8p1cPJQbhZSwaKO3p+bU3Rgny+OM5gJMKHWHvJKan/fsE5RUzEjRQolv9DzPOSVWfSOHz0lLxK19eA==
+page@^1.11.6:
+  version "1.11.6"
+  resolved "https://registry.yarnpkg.com/page/-/page-1.11.6.tgz#5ef4efc7073749b8085ccdaa0dcd7c9e0de12fe3"
+  integrity sha512-P6e2JfzkBrPeFCIPplLP7vDDiU84RUUZMrWdsH4ZBGJ8OosnwFkcUkBHp1DTIjuipLliw9yQn/ZJsXZvarsO+g==
   dependencies:
     path-to-regexp "~1.2.1"
 
@@ -456,10 +449,10 @@
     "@polymer/polymer" "^3.0.2"
     "@webcomponents/webcomponentsjs" "^2.0.3"
 
-rxjs@^6.6.2:
-  version "6.6.2"
-  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.2.tgz#8096a7ac03f2cc4fe5860ef6e572810d9e01c0d2"
-  integrity sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg==
+rxjs@^6.6.7:
+  version "6.6.7"
+  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9"
+  integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==
   dependencies:
     tslib "^1.9.0"
 
@@ -469,6 +462,6 @@
   integrity sha512-ntz8P6DLEFpx7gikeXZ4gSi3APE2D+BP0rKnnaBzED+Lm8je8nkNcayy6kGWPEDWMFbtm+Yvd1ONFaXcsVWn2w==
 
 tslib@^1.9.0:
-  version "1.13.0"
-  resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
-  integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
+  version "1.14.1"
+  resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
+  integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
diff --git a/polygerrit-ui/package.json b/polygerrit-ui/package.json
index c01ef56..3aa0c92 100644
--- a/polygerrit-ui/package.json
+++ b/polygerrit-ui/package.json
@@ -3,24 +3,24 @@
   "description": "Gerrit Code Review - Polygerrit dev dependencies",
   "browser": true,
   "dependencies": {
-    "@types/chai": "^4.2.14",
-    "@types/lodash": "^4.14.162",
-    "@types/mocha": "^8.0.3",
-    "@types/sinon": "^9.0.8"
+    "@types/chai": "^4.2.16",
+    "@types/lodash": "^4.14.168",
+    "@types/mocha": "^8.2.2",
+    "@types/sinon": "^10.0.0"
   },
   "devDependencies": {
     "@open-wc/karma-esm": "^2.16.16",
     "@polymer/iron-test-helpers": "^3.0.1",
     "@polymer/test-fixture": "^4.0.2",
     "accessibility-developer-tools": "^2.12.0",
-    "chai": "^4.2.0",
+    "chai": "^4.3.4",
     "karma": "^4.4.1",
     "karma-chrome-launcher": "^3.1.0",
     "karma-mocha": "^2.0.1",
     "karma-mocha-reporter": "^2.2.5",
-    "lodash": "^4.17.15",
-    "mocha": "7.2.0",
-    "sinon": "^9.0.2",
+    "lodash": "^4.17.21",
+    "mocha": "8.3.2",
+    "sinon": "^10.0.0",
     "source-map-support": "^0.5.19"
   },
   "license": "Apache-2.0",
diff --git a/polygerrit-ui/yarn.lock b/polygerrit-ui/yarn.lock
index 2acd478..271b295 100644
--- a/polygerrit-ui/yarn.lock
+++ b/polygerrit-ui/yarn.lock
@@ -2,387 +2,428 @@
 # yarn lockfile v1
 
 
-"@babel/code-frame@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a"
-  integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==
+"@babel/code-frame@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658"
+  integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==
   dependencies:
-    "@babel/highlight" "^7.10.4"
+    "@babel/highlight" "^7.12.13"
 
-"@babel/compat-data@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.10.4.tgz#706a6484ee6f910b719b696a9194f8da7d7ac241"
-  integrity sha512-t+rjExOrSVvjQQXNp5zAIYDp00KjdvGl/TpDX5REPr0S9IAIPQMTilcfG6q8c0QFmj9lSTVySV2VTsyggvtNIw==
-  dependencies:
-    browserslist "^4.12.0"
-    invariant "^2.2.4"
-    semver "^5.5.0"
+"@babel/compat-data@^7.13.0", "@babel/compat-data@^7.13.12", "@babel/compat-data@^7.13.8":
+  version "7.13.12"
+  resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.13.12.tgz#a8a5ccac19c200f9dd49624cac6e19d7be1236a1"
+  integrity sha512-3eJJ841uKxeV8dcN/2yGEUy+RfgQspPEgQat85umsE1rotuquQ2AbIub4S6j7c50a2d+4myc+zSlnXeIHrOnhQ==
 
-"@babel/core@^7.9.0":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.10.4.tgz#780e8b83e496152f8dd7df63892b2e052bf1d51d"
-  integrity sha512-3A0tS0HWpy4XujGc7QtOIHTeNwUgWaZc/WuS5YQrfhU67jnVmsD6OGPc1AKHH0LJHQICGncy3+YUjIhVlfDdcA==
+"@babel/core@^7.11.1":
+  version "7.13.14"
+  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.13.14.tgz#8e46ebbaca460a63497c797e574038ab04ae6d06"
+  integrity sha512-wZso/vyF4ki0l0znlgM4inxbdrUvCb+cVz8grxDq+6C9k6qbqoIJteQOKicaKjCipU3ISV+XedCqpL2RJJVehA==
   dependencies:
-    "@babel/code-frame" "^7.10.4"
-    "@babel/generator" "^7.10.4"
-    "@babel/helper-module-transforms" "^7.10.4"
-    "@babel/helpers" "^7.10.4"
-    "@babel/parser" "^7.10.4"
-    "@babel/template" "^7.10.4"
-    "@babel/traverse" "^7.10.4"
-    "@babel/types" "^7.10.4"
+    "@babel/code-frame" "^7.12.13"
+    "@babel/generator" "^7.13.9"
+    "@babel/helper-compilation-targets" "^7.13.13"
+    "@babel/helper-module-transforms" "^7.13.14"
+    "@babel/helpers" "^7.13.10"
+    "@babel/parser" "^7.13.13"
+    "@babel/template" "^7.12.13"
+    "@babel/traverse" "^7.13.13"
+    "@babel/types" "^7.13.14"
     convert-source-map "^1.7.0"
     debug "^4.1.0"
-    gensync "^1.0.0-beta.1"
+    gensync "^1.0.0-beta.2"
     json5 "^2.1.2"
-    lodash "^4.17.13"
-    resolve "^1.3.2"
-    semver "^5.4.1"
+    semver "^6.3.0"
     source-map "^0.5.0"
 
-"@babel/generator@^7.10.4", "@babel/generator@^7.4.0":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.10.4.tgz#e49eeed9fe114b62fa5b181856a43a5e32f5f243"
-  integrity sha512-toLIHUIAgcQygFZRAQcsLQV3CBuX6yOIru1kJk/qqqvcRmZrYe6WavZTSG+bB8MxhnL9YPf+pKQfuiP161q7ng==
+"@babel/generator@^7.13.9", "@babel/generator@^7.4.0":
+  version "7.13.9"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.13.9.tgz#3a7aa96f9efb8e2be42d38d80e2ceb4c64d8de39"
+  integrity sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==
   dependencies:
-    "@babel/types" "^7.10.4"
+    "@babel/types" "^7.13.0"
     jsesc "^2.5.1"
-    lodash "^4.17.13"
     source-map "^0.5.0"
 
-"@babel/helper-annotate-as-pure@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3"
-  integrity sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==
+"@babel/helper-annotate-as-pure@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.13.tgz#0f58e86dfc4bb3b1fcd7db806570e177d439b6ab"
+  integrity sha512-7YXfX5wQ5aYM/BOlbSccHDbuXXFPxeoUmfWtz8le2yTkTZc+BxsiEnENFoi2SlmA8ewDkG2LgIMIVzzn2h8kfw==
   dependencies:
-    "@babel/types" "^7.10.4"
+    "@babel/types" "^7.12.13"
 
-"@babel/helper-builder-binary-assignment-operator-visitor@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz#bb0b75f31bf98cbf9ff143c1ae578b87274ae1a3"
-  integrity sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==
+"@babel/helper-builder-binary-assignment-operator-visitor@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.12.13.tgz#6bc20361c88b0a74d05137a65cac8d3cbf6f61fc"
+  integrity sha512-CZOv9tGphhDRlVjVkAgm8Nhklm9RzSmWpX2my+t7Ua/KT616pEzXsQCjinzvkRvHWJ9itO4f296efroX23XCMA==
   dependencies:
-    "@babel/helper-explode-assignable-expression" "^7.10.4"
-    "@babel/types" "^7.10.4"
+    "@babel/helper-explode-assignable-expression" "^7.12.13"
+    "@babel/types" "^7.12.13"
 
-"@babel/helper-compilation-targets@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz#804ae8e3f04376607cc791b9d47d540276332bd2"
-  integrity sha512-a3rYhlsGV0UHNDvrtOXBg8/OpfV0OKTkxKPzIplS1zpx7CygDcWWxckxZeDd3gzPzC4kUT0A4nVFDK0wGMh4MQ==
+"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.13.10", "@babel/helper-compilation-targets@^7.13.13", "@babel/helper-compilation-targets@^7.13.8":
+  version "7.13.13"
+  resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.13.tgz#2b2972a0926474853f41e4adbc69338f520600e5"
+  integrity sha512-q1kcdHNZehBwD9jYPh3WyXcsFERi39X4I59I3NadciWtNDyZ6x+GboOxncFK0kXlKIv6BJm5acncehXWUjWQMQ==
   dependencies:
-    "@babel/compat-data" "^7.10.4"
-    browserslist "^4.12.0"
-    invariant "^2.2.4"
-    levenary "^1.1.1"
-    semver "^5.5.0"
+    "@babel/compat-data" "^7.13.12"
+    "@babel/helper-validator-option" "^7.12.17"
+    browserslist "^4.14.5"
+    semver "^6.3.0"
 
-"@babel/helper-create-class-features-plugin@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.4.tgz#2d4015d0136bd314103a70d84a7183e4b344a355"
-  integrity sha512-9raUiOsXPxzzLjCXeosApJItoMnX3uyT4QdM2UldffuGApNrF8e938MwNpDCK9CPoyxrEoCgT+hObJc3mZa6lQ==
+"@babel/helper-create-class-features-plugin@^7.13.0":
+  version "7.13.11"
+  resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.13.11.tgz#30d30a005bca2c953f5653fc25091a492177f4f6"
+  integrity sha512-ays0I7XYq9xbjCSvT+EvysLgfc3tOkwCULHjrnscGT3A9qD4sk3wXnJ3of0MAWsWGjdinFvajHU2smYuqXKMrw==
   dependencies:
-    "@babel/helper-function-name" "^7.10.4"
-    "@babel/helper-member-expression-to-functions" "^7.10.4"
-    "@babel/helper-optimise-call-expression" "^7.10.4"
-    "@babel/helper-plugin-utils" "^7.10.4"
-    "@babel/helper-replace-supers" "^7.10.4"
-    "@babel/helper-split-export-declaration" "^7.10.4"
+    "@babel/helper-function-name" "^7.12.13"
+    "@babel/helper-member-expression-to-functions" "^7.13.0"
+    "@babel/helper-optimise-call-expression" "^7.12.13"
+    "@babel/helper-replace-supers" "^7.13.0"
+    "@babel/helper-split-export-declaration" "^7.12.13"
 
-"@babel/helper-create-regexp-features-plugin@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz#fdd60d88524659a0b6959c0579925e425714f3b8"
-  integrity sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g==
+"@babel/helper-create-regexp-features-plugin@^7.12.13":
+  version "7.12.17"
+  resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.17.tgz#a2ac87e9e319269ac655b8d4415e94d38d663cb7"
+  integrity sha512-p2VGmBu9oefLZ2nQpgnEnG0ZlRPvL8gAGvPUMQwUdaE8k49rOMuZpOwdQoy5qJf6K8jL3bcAMhVUlHAjIgJHUg==
   dependencies:
-    "@babel/helper-annotate-as-pure" "^7.10.4"
-    "@babel/helper-regex" "^7.10.4"
-    regexpu-core "^4.7.0"
+    "@babel/helper-annotate-as-pure" "^7.12.13"
+    regexpu-core "^4.7.1"
 
-"@babel/helper-define-map@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.10.4.tgz#f037ad794264f729eda1889f4ee210b870999092"
-  integrity sha512-nIij0oKErfCnLUCWaCaHW0Bmtl2RO9cN7+u2QT8yqTywgALKlyUVOvHDElh+b5DwVC6YB1FOYFOTWcN/+41EDA==
+"@babel/helper-define-polyfill-provider@^0.1.5":
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.1.5.tgz#3c2f91b7971b9fc11fe779c945c014065dea340e"
+  integrity sha512-nXuzCSwlJ/WKr8qxzW816gwyT6VZgiJG17zR40fou70yfAcqjoNyTLl/DQ+FExw5Hx5KNqshmN8Ldl/r2N7cTg==
   dependencies:
-    "@babel/helper-function-name" "^7.10.4"
-    "@babel/types" "^7.10.4"
-    lodash "^4.17.13"
+    "@babel/helper-compilation-targets" "^7.13.0"
+    "@babel/helper-module-imports" "^7.12.13"
+    "@babel/helper-plugin-utils" "^7.13.0"
+    "@babel/traverse" "^7.13.0"
+    debug "^4.1.1"
+    lodash.debounce "^4.0.8"
+    resolve "^1.14.2"
+    semver "^6.1.2"
 
-"@babel/helper-explode-assignable-expression@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.10.4.tgz#40a1cd917bff1288f699a94a75b37a1a2dbd8c7c"
-  integrity sha512-4K71RyRQNPRrR85sr5QY4X3VwG4wtVoXZB9+L3r1Gp38DhELyHCtovqydRi7c1Ovb17eRGiQ/FD5s8JdU0Uy5A==
+"@babel/helper-explode-assignable-expression@^7.12.13":
+  version "7.13.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.13.0.tgz#17b5c59ff473d9f956f40ef570cf3a76ca12657f"
+  integrity sha512-qS0peLTDP8kOisG1blKbaoBg/o9OSa1qoumMjTK5pM+KDTtpxpsiubnCGP34vK8BXGcb2M9eigwgvoJryrzwWA==
   dependencies:
-    "@babel/traverse" "^7.10.4"
-    "@babel/types" "^7.10.4"
+    "@babel/types" "^7.13.0"
 
-"@babel/helper-function-name@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a"
-  integrity sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==
+"@babel/helper-function-name@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz#93ad656db3c3c2232559fd7b2c3dbdcbe0eb377a"
+  integrity sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==
   dependencies:
-    "@babel/helper-get-function-arity" "^7.10.4"
-    "@babel/template" "^7.10.4"
-    "@babel/types" "^7.10.4"
+    "@babel/helper-get-function-arity" "^7.12.13"
+    "@babel/template" "^7.12.13"
+    "@babel/types" "^7.12.13"
 
-"@babel/helper-get-function-arity@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2"
-  integrity sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==
+"@babel/helper-get-function-arity@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz#bc63451d403a3b3082b97e1d8b3fe5bd4091e583"
+  integrity sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==
   dependencies:
-    "@babel/types" "^7.10.4"
+    "@babel/types" "^7.12.13"
 
-"@babel/helper-hoist-variables@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz#d49b001d1d5a68ca5e6604dda01a6297f7c9381e"
-  integrity sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==
+"@babel/helper-hoist-variables@^7.13.0":
+  version "7.13.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.13.0.tgz#5d5882e855b5c5eda91e0cadc26c6e7a2c8593d8"
+  integrity sha512-0kBzvXiIKfsCA0y6cFEIJf4OdzfpRuNk4+YTeHZpGGc666SATFKTz6sRncwFnQk7/ugJ4dSrCj6iJuvW4Qwr2g==
   dependencies:
-    "@babel/types" "^7.10.4"
+    "@babel/traverse" "^7.13.0"
+    "@babel/types" "^7.13.0"
 
-"@babel/helper-member-expression-to-functions@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.4.tgz#7cd04b57dfcf82fce9aeae7d4e4452fa31b8c7c4"
-  integrity sha512-m5j85pK/KZhuSdM/8cHUABQTAslV47OjfIB9Cc7P+PvlAoBzdb79BGNfw8RhT5Mq3p+xGd0ZfAKixbrUZx0C7A==
+"@babel/helper-member-expression-to-functions@^7.13.0", "@babel/helper-member-expression-to-functions@^7.13.12":
+  version "7.13.12"
+  resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz#dfe368f26d426a07299d8d6513821768216e6d72"
+  integrity sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw==
   dependencies:
-    "@babel/types" "^7.10.4"
+    "@babel/types" "^7.13.12"
 
-"@babel/helper-module-imports@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620"
-  integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==
+"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.13.12":
+  version "7.13.12"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz#c6a369a6f3621cb25da014078684da9196b61977"
+  integrity sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA==
   dependencies:
-    "@babel/types" "^7.10.4"
+    "@babel/types" "^7.13.12"
 
-"@babel/helper-module-transforms@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.10.4.tgz#ca1f01fdb84e48c24d7506bb818c961f1da8805d"
-  integrity sha512-Er2FQX0oa3nV7eM1o0tNCTx7izmQtwAQsIiaLRWtavAAEcskb0XJ5OjJbVrYXWOTr8om921Scabn4/tzlx7j1Q==
+"@babel/helper-module-transforms@^7.13.0", "@babel/helper-module-transforms@^7.13.14":
+  version "7.13.14"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.13.14.tgz#e600652ba48ccb1641775413cb32cfa4e8b495ef"
+  integrity sha512-QuU/OJ0iAOSIatyVZmfqB0lbkVP0kDRiKj34xy+QNsnVZi/PA6BoSoreeqnxxa9EHFAIL0R9XOaAR/G9WlIy5g==
   dependencies:
-    "@babel/helper-module-imports" "^7.10.4"
-    "@babel/helper-replace-supers" "^7.10.4"
-    "@babel/helper-simple-access" "^7.10.4"
-    "@babel/helper-split-export-declaration" "^7.10.4"
-    "@babel/template" "^7.10.4"
-    "@babel/types" "^7.10.4"
-    lodash "^4.17.13"
+    "@babel/helper-module-imports" "^7.13.12"
+    "@babel/helper-replace-supers" "^7.13.12"
+    "@babel/helper-simple-access" "^7.13.12"
+    "@babel/helper-split-export-declaration" "^7.12.13"
+    "@babel/helper-validator-identifier" "^7.12.11"
+    "@babel/template" "^7.12.13"
+    "@babel/traverse" "^7.13.13"
+    "@babel/types" "^7.13.14"
 
-"@babel/helper-optimise-call-expression@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673"
-  integrity sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==
+"@babel/helper-optimise-call-expression@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz#5c02d171b4c8615b1e7163f888c1c81c30a2aaea"
+  integrity sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==
   dependencies:
-    "@babel/types" "^7.10.4"
+    "@babel/types" "^7.12.13"
 
-"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375"
-  integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==
+"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
+  version "7.13.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz#806526ce125aed03373bc416a828321e3a6a33af"
+  integrity sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==
 
-"@babel/helper-regex@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.10.4.tgz#59b373daaf3458e5747dece71bbaf45f9676af6d"
-  integrity sha512-inWpnHGgtg5NOF0eyHlC0/74/VkdRITY9dtTpB2PrxKKn+AkVMRiZz/Adrx+Ssg+MLDesi2zohBW6MVq6b4pOQ==
+"@babel/helper-remap-async-to-generator@^7.13.0":
+  version "7.13.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.13.0.tgz#376a760d9f7b4b2077a9dd05aa9c3927cadb2209"
+  integrity sha512-pUQpFBE9JvC9lrQbpX0TmeNIy5s7GnZjna2lhhcHC7DzgBs6fWn722Y5cfwgrtrqc7NAJwMvOa0mKhq6XaE4jg==
   dependencies:
-    lodash "^4.17.13"
+    "@babel/helper-annotate-as-pure" "^7.12.13"
+    "@babel/helper-wrap-function" "^7.13.0"
+    "@babel/types" "^7.13.0"
 
-"@babel/helper-remap-async-to-generator@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.10.4.tgz#fce8bea4e9690bbe923056ded21e54b4e8b68ed5"
-  integrity sha512-86Lsr6NNw3qTNl+TBcF1oRZMaVzJtbWTyTko+CQL/tvNvcGYEFKbLXDPxtW0HKk3McNOk4KzY55itGWCAGK5tg==
+"@babel/helper-replace-supers@^7.12.13", "@babel/helper-replace-supers@^7.13.0", "@babel/helper-replace-supers@^7.13.12":
+  version "7.13.12"
+  resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.13.12.tgz#6442f4c1ad912502481a564a7386de0c77ff3804"
+  integrity sha512-Gz1eiX+4yDO8mT+heB94aLVNCL+rbuT2xy4YfyNqu8F+OI6vMvJK891qGBTqL9Uc8wxEvRW92Id6G7sDen3fFw==
   dependencies:
-    "@babel/helper-annotate-as-pure" "^7.10.4"
-    "@babel/helper-wrap-function" "^7.10.4"
-    "@babel/template" "^7.10.4"
-    "@babel/traverse" "^7.10.4"
-    "@babel/types" "^7.10.4"
+    "@babel/helper-member-expression-to-functions" "^7.13.12"
+    "@babel/helper-optimise-call-expression" "^7.12.13"
+    "@babel/traverse" "^7.13.0"
+    "@babel/types" "^7.13.12"
 
-"@babel/helper-replace-supers@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz#d585cd9388ea06e6031e4cd44b6713cbead9e6cf"
-  integrity sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A==
+"@babel/helper-simple-access@^7.12.13", "@babel/helper-simple-access@^7.13.12":
+  version "7.13.12"
+  resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz#dd6c538afb61819d205a012c31792a39c7a5eaf6"
+  integrity sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA==
   dependencies:
-    "@babel/helper-member-expression-to-functions" "^7.10.4"
-    "@babel/helper-optimise-call-expression" "^7.10.4"
-    "@babel/traverse" "^7.10.4"
-    "@babel/types" "^7.10.4"
+    "@babel/types" "^7.13.12"
 
-"@babel/helper-simple-access@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz#0f5ccda2945277a2a7a2d3a821e15395edcf3461"
-  integrity sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw==
+"@babel/helper-skip-transparent-expression-wrappers@^7.12.1":
+  version "7.12.1"
+  resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz#462dc63a7e435ade8468385c63d2b84cce4b3cbf"
+  integrity sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA==
   dependencies:
-    "@babel/template" "^7.10.4"
-    "@babel/types" "^7.10.4"
+    "@babel/types" "^7.12.1"
 
-"@babel/helper-split-export-declaration@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.4.tgz#2c70576eaa3b5609b24cb99db2888cc3fc4251d1"
-  integrity sha512-pySBTeoUff56fL5CBU2hWm9TesA4r/rOkI9DyJLvvgz09MB9YtfIYe3iBriVaYNaPe+Alua0vBIOVOLs2buWhg==
+"@babel/helper-split-export-declaration@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz#e9430be00baf3e88b0e13e6f9d4eaf2136372b05"
+  integrity sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==
   dependencies:
-    "@babel/types" "^7.10.4"
+    "@babel/types" "^7.12.13"
 
-"@babel/helper-validator-identifier@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2"
-  integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==
+"@babel/helper-validator-identifier@^7.12.11":
+  version "7.12.11"
+  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed"
+  integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==
 
-"@babel/helper-wrap-function@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz#8a6f701eab0ff39f765b5a1cfef409990e624b87"
-  integrity sha512-6py45WvEF0MhiLrdxtRjKjufwLL1/ob2qDJgg5JgNdojBAZSAKnAjkyOCNug6n+OBl4VW76XjvgSFTdaMcW0Ug==
+"@babel/helper-validator-option@^7.12.17":
+  version "7.12.17"
+  resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz#d1fbf012e1a79b7eebbfdc6d270baaf8d9eb9831"
+  integrity sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==
+
+"@babel/helper-wrap-function@^7.13.0":
+  version "7.13.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.13.0.tgz#bdb5c66fda8526ec235ab894ad53a1235c79fcc4"
+  integrity sha512-1UX9F7K3BS42fI6qd2A4BjKzgGjToscyZTdp1DjknHLCIvpgne6918io+aL5LXFcER/8QWiwpoY902pVEqgTXA==
   dependencies:
-    "@babel/helper-function-name" "^7.10.4"
-    "@babel/template" "^7.10.4"
-    "@babel/traverse" "^7.10.4"
-    "@babel/types" "^7.10.4"
+    "@babel/helper-function-name" "^7.12.13"
+    "@babel/template" "^7.12.13"
+    "@babel/traverse" "^7.13.0"
+    "@babel/types" "^7.13.0"
 
-"@babel/helpers@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.10.4.tgz#2abeb0d721aff7c0a97376b9e1f6f65d7a475044"
-  integrity sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA==
+"@babel/helpers@^7.13.10":
+  version "7.13.10"
+  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.13.10.tgz#fd8e2ba7488533cdeac45cc158e9ebca5e3c7df8"
+  integrity sha512-4VO883+MWPDUVRF3PhiLBUFHoX/bsLTGFpFK/HqvvfBZz2D57u9XzPVNFVBTc0PW/CWR9BXTOKt8NF4DInUHcQ==
   dependencies:
-    "@babel/template" "^7.10.4"
-    "@babel/traverse" "^7.10.4"
-    "@babel/types" "^7.10.4"
+    "@babel/template" "^7.12.13"
+    "@babel/traverse" "^7.13.0"
+    "@babel/types" "^7.13.0"
 
-"@babel/highlight@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143"
-  integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==
+"@babel/highlight@^7.12.13":
+  version "7.13.10"
+  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.13.10.tgz#a8b2a66148f5b27d666b15d81774347a731d52d1"
+  integrity sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==
   dependencies:
-    "@babel/helper-validator-identifier" "^7.10.4"
+    "@babel/helper-validator-identifier" "^7.12.11"
     chalk "^2.0.0"
     js-tokens "^4.0.0"
 
-"@babel/parser@^7.1.0", "@babel/parser@^7.10.4", "@babel/parser@^7.4.3":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.4.tgz#9eedf27e1998d87739fb5028a5120557c06a1a64"
-  integrity sha512-8jHII4hf+YVDsskTF6WuMB3X4Eh+PsUkC2ljq22so5rHvH+T8BzyL94VOdyFLNR8tBSVXOTbNHOKpR4TfRxVtA==
+"@babel/parser@^7.1.0", "@babel/parser@^7.12.13", "@babel/parser@^7.13.13", "@babel/parser@^7.4.3":
+  version "7.13.13"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.13.tgz#42f03862f4aed50461e543270916b47dd501f0df"
+  integrity sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw==
 
-"@babel/plugin-proposal-async-generator-functions@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.4.tgz#4b65abb3d9bacc6c657aaa413e56696f9f170fc6"
-  integrity sha512-MJbxGSmejEFVOANAezdO39SObkURO5o/8b6fSH6D1pi9RZQt+ldppKPXfqgUWpSQ9asM6xaSaSJIaeWMDRP0Zg==
+"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.13.12":
+  version "7.13.12"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.13.12.tgz#a3484d84d0b549f3fc916b99ee4783f26fabad2a"
+  integrity sha512-d0u3zWKcoZf379fOeJdr1a5WPDny4aOFZ6hlfKivgK0LY7ZxNfoaHL2fWwdGtHyVvra38FC+HVYkO+byfSA8AQ==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
-    "@babel/helper-remap-async-to-generator" "^7.10.4"
-    "@babel/plugin-syntax-async-generators" "^7.8.0"
+    "@babel/helper-plugin-utils" "^7.13.0"
+    "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1"
+    "@babel/plugin-proposal-optional-chaining" "^7.13.12"
 
-"@babel/plugin-proposal-class-properties@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz#a33bf632da390a59c7a8c570045d1115cd778807"
-  integrity sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg==
+"@babel/plugin-proposal-async-generator-functions@^7.13.8":
+  version "7.13.8"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.13.8.tgz#87aacb574b3bc4b5603f6fe41458d72a5a2ec4b1"
+  integrity sha512-rPBnhj+WgoSmgq+4gQUtXx/vOcU+UYtjy1AA/aeD61Hwj410fwYyqfUcRP3lR8ucgliVJL/G7sXcNUecC75IXA==
   dependencies:
-    "@babel/helper-create-class-features-plugin" "^7.10.4"
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.13.0"
+    "@babel/helper-remap-async-to-generator" "^7.13.0"
+    "@babel/plugin-syntax-async-generators" "^7.8.4"
 
-"@babel/plugin-proposal-dynamic-import@^7.10.4", "@babel/plugin-proposal-dynamic-import@^7.8.3":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz#ba57a26cb98b37741e9d5bca1b8b0ddf8291f17e"
-  integrity sha512-up6oID1LeidOOASNXgv/CFbgBqTuKJ0cJjz6An5tWD+NVBNlp3VNSBxv2ZdU7SYl3NxJC7agAQDApZusV6uFwQ==
+"@babel/plugin-proposal-class-properties@^7.13.0":
+  version "7.13.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.13.0.tgz#146376000b94efd001e57a40a88a525afaab9f37"
+  integrity sha512-KnTDjFNC1g+45ka0myZNvSBFLhNCLN+GeGYLDEA8Oq7MZ6yMgfLoIRh86GRT0FjtJhZw8JyUskP9uvj5pHM9Zg==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
-    "@babel/plugin-syntax-dynamic-import" "^7.8.0"
+    "@babel/helper-create-class-features-plugin" "^7.13.0"
+    "@babel/helper-plugin-utils" "^7.13.0"
 
-"@babel/plugin-proposal-json-strings@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.4.tgz#593e59c63528160233bd321b1aebe0820c2341db"
-  integrity sha512-fCL7QF0Jo83uy1K0P2YXrfX11tj3lkpN7l4dMv9Y9VkowkhkQDwFHFd8IiwyK5MZjE8UpbgokkgtcReH88Abaw==
+"@babel/plugin-proposal-dynamic-import@^7.10.4", "@babel/plugin-proposal-dynamic-import@^7.13.8":
+  version "7.13.8"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.13.8.tgz#876a1f6966e1dec332e8c9451afda3bebcdf2e1d"
+  integrity sha512-ONWKj0H6+wIRCkZi9zSbZtE/r73uOhMVHh256ys0UzfM7I3d4n+spZNWjOnJv2gzopumP2Wxi186vI8N0Y2JyQ==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
-    "@babel/plugin-syntax-json-strings" "^7.8.0"
+    "@babel/helper-plugin-utils" "^7.13.0"
+    "@babel/plugin-syntax-dynamic-import" "^7.8.3"
 
-"@babel/plugin-proposal-nullish-coalescing-operator@^7.10.4", "@babel/plugin-proposal-nullish-coalescing-operator@^7.8.3":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz#02a7e961fc32e6d5b2db0649e01bf80ddee7e04a"
-  integrity sha512-wq5n1M3ZUlHl9sqT2ok1T2/MTt6AXE0e1Lz4WzWBr95LsAZ5qDXe4KnFuauYyEyLiohvXFMdbsOTMyLZs91Zlw==
+"@babel/plugin-proposal-export-namespace-from@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.13.tgz#393be47a4acd03fa2af6e3cde9b06e33de1b446d"
+  integrity sha512-INAgtFo4OnLN3Y/j0VwAgw3HDXcDtX+C/erMvWzuV9v71r7urb6iyMXu7eM9IgLr1ElLlOkaHjJ0SbCmdOQ3Iw==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
-    "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0"
+    "@babel/helper-plugin-utils" "^7.12.13"
+    "@babel/plugin-syntax-export-namespace-from" "^7.8.3"
 
-"@babel/plugin-proposal-numeric-separator@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.4.tgz#ce1590ff0a65ad12970a609d78855e9a4c1aef06"
-  integrity sha512-73/G7QoRoeNkLZFxsoCCvlg4ezE4eM+57PnOqgaPOozd5myfj7p0muD1mRVJvbUWbOzD+q3No2bWbaKy+DJ8DA==
+"@babel/plugin-proposal-json-strings@^7.13.8":
+  version "7.13.8"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.13.8.tgz#bf1fb362547075afda3634ed31571c5901afef7b"
+  integrity sha512-w4zOPKUFPX1mgvTmL/fcEqy34hrQ1CRcGxdphBc6snDnnqJ47EZDIyop6IwXzAC8G916hsIuXB2ZMBCExC5k7Q==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.13.0"
+    "@babel/plugin-syntax-json-strings" "^7.8.3"
+
+"@babel/plugin-proposal-logical-assignment-operators@^7.13.8":
+  version "7.13.8"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.13.8.tgz#93fa78d63857c40ce3c8c3315220fd00bfbb4e1a"
+  integrity sha512-aul6znYB4N4HGweImqKn59Su9RS8lbUIqxtXTOcAGtNIDczoEFv+l1EhmX8rUBp3G1jMjKJm8m0jXVp63ZpS4A==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.13.0"
+    "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4"
+
+"@babel/plugin-proposal-nullish-coalescing-operator@^7.10.4", "@babel/plugin-proposal-nullish-coalescing-operator@^7.13.8":
+  version "7.13.8"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.13.8.tgz#3730a31dafd3c10d8ccd10648ed80a2ac5472ef3"
+  integrity sha512-iePlDPBn//UhxExyS9KyeYU7RM9WScAG+D3Hhno0PLJebAEpDZMocbDe64eqynhNAnwz/vZoL/q/QB2T1OH39A==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.13.0"
+    "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
+
+"@babel/plugin-proposal-numeric-separator@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.13.tgz#bd9da3188e787b5120b4f9d465a8261ce67ed1db"
+  integrity sha512-O1jFia9R8BUCl3ZGB7eitaAPu62TXJRHn7rh+ojNERCFyqRwJMTmhz+tJ+k0CwI6CLjX/ee4qW74FSqlq9I35w==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.12.13"
     "@babel/plugin-syntax-numeric-separator" "^7.10.4"
 
-"@babel/plugin-proposal-object-rest-spread@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.10.4.tgz#50129ac216b9a6a55b3853fdd923e74bf553a4c0"
-  integrity sha512-6vh4SqRuLLarjgeOf4EaROJAHjvu9Gl+/346PbDH9yWbJyfnJ/ah3jmYKYtswEyCoWZiidvVHjHshd4WgjB9BA==
+"@babel/plugin-proposal-object-rest-spread@^7.13.8":
+  version "7.13.8"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.13.8.tgz#5d210a4d727d6ce3b18f9de82cc99a3964eed60a"
+  integrity sha512-DhB2EuB1Ih7S3/IRX5AFVgZ16k3EzfRbq97CxAVI1KSYcW+lexV8VZb7G7L8zuPVSdQMRn0kiBpf/Yzu9ZKH0g==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
-    "@babel/plugin-syntax-object-rest-spread" "^7.8.0"
-    "@babel/plugin-transform-parameters" "^7.10.4"
+    "@babel/compat-data" "^7.13.8"
+    "@babel/helper-compilation-targets" "^7.13.8"
+    "@babel/helper-plugin-utils" "^7.13.0"
+    "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
+    "@babel/plugin-transform-parameters" "^7.13.0"
 
-"@babel/plugin-proposal-optional-catch-binding@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.4.tgz#31c938309d24a78a49d68fdabffaa863758554dd"
-  integrity sha512-LflT6nPh+GK2MnFiKDyLiqSqVHkQnVf7hdoAvyTnnKj9xB3docGRsdPuxp6qqqW19ifK3xgc9U5/FwrSaCNX5g==
+"@babel/plugin-proposal-optional-catch-binding@^7.13.8":
+  version "7.13.8"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.13.8.tgz#3ad6bd5901506ea996fc31bdcf3ccfa2bed71107"
+  integrity sha512-0wS/4DUF1CuTmGo+NiaHfHcVSeSLj5S3e6RivPTg/2k3wOv3jO35tZ6/ZWsQhQMvdgI7CwphjQa/ccarLymHVA==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
-    "@babel/plugin-syntax-optional-catch-binding" "^7.8.0"
+    "@babel/helper-plugin-utils" "^7.13.0"
+    "@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
 
-"@babel/plugin-proposal-optional-chaining@^7.10.4", "@babel/plugin-proposal-optional-chaining@^7.9.0":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.10.4.tgz#750f1255e930a1f82d8cdde45031f81a0d0adff7"
-  integrity sha512-ZIhQIEeavTgouyMSdZRap4VPPHqJJ3NEs2cuHs5p0erH+iz6khB0qfgU8g7UuJkG88+fBMy23ZiU+nuHvekJeQ==
+"@babel/plugin-proposal-optional-chaining@^7.11.0", "@babel/plugin-proposal-optional-chaining@^7.13.12":
+  version "7.13.12"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.13.12.tgz#ba9feb601d422e0adea6760c2bd6bbb7bfec4866"
+  integrity sha512-fcEdKOkIB7Tf4IxrgEVeFC4zeJSTr78no9wTdBuZZbqF64kzllU0ybo2zrzm7gUQfxGhBgq4E39oRs8Zx/RMYQ==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
-    "@babel/plugin-syntax-optional-chaining" "^7.8.0"
+    "@babel/helper-plugin-utils" "^7.13.0"
+    "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1"
+    "@babel/plugin-syntax-optional-chaining" "^7.8.3"
 
-"@babel/plugin-proposal-private-methods@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.4.tgz#b160d972b8fdba5c7d111a145fc8c421fc2a6909"
-  integrity sha512-wh5GJleuI8k3emgTg5KkJK6kHNsGEr0uBTDBuQUBJwckk9xs1ez79ioheEVVxMLyPscB0LfkbVHslQqIzWV6Bw==
+"@babel/plugin-proposal-private-methods@^7.13.0":
+  version "7.13.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.13.0.tgz#04bd4c6d40f6e6bbfa2f57e2d8094bad900ef787"
+  integrity sha512-MXyyKQd9inhx1kDYPkFRVOBXQ20ES8Pto3T7UZ92xj2mY0EVD8oAVzeyYuVfy/mxAdTSIayOvg+aVzcHV2bn6Q==
   dependencies:
-    "@babel/helper-create-class-features-plugin" "^7.10.4"
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-create-class-features-plugin" "^7.13.0"
+    "@babel/helper-plugin-utils" "^7.13.0"
 
-"@babel/plugin-proposal-unicode-property-regex@^7.10.4", "@babel/plugin-proposal-unicode-property-regex@^7.4.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz#4483cda53041ce3413b7fe2f00022665ddfaa75d"
-  integrity sha512-H+3fOgPnEXFL9zGYtKQe4IDOPKYlZdF1kqFDQRRb8PK4B8af1vAGK04tF5iQAAsui+mHNBQSAtd2/ndEDe9wuA==
+"@babel/plugin-proposal-unicode-property-regex@^7.12.13", "@babel/plugin-proposal-unicode-property-regex@^7.4.4":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.13.tgz#bebde51339be829c17aaaaced18641deb62b39ba"
+  integrity sha512-XyJmZidNfofEkqFV5VC/bLabGmO5QzenPO/YOfGuEbgU+2sSwMmio3YLb4WtBgcmmdwZHyVyv8on77IUjQ5Gvg==
   dependencies:
-    "@babel/helper-create-regexp-features-plugin" "^7.10.4"
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-create-regexp-features-plugin" "^7.12.13"
+    "@babel/helper-plugin-utils" "^7.12.13"
 
-"@babel/plugin-syntax-async-generators@^7.8.0":
+"@babel/plugin-syntax-async-generators@^7.8.4":
   version "7.8.4"
   resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
   integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==
   dependencies:
     "@babel/helper-plugin-utils" "^7.8.0"
 
-"@babel/plugin-syntax-class-properties@^7.10.4", "@babel/plugin-syntax-class-properties@^7.8.3":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.4.tgz#6644e6a0baa55a61f9e3231f6c9eeb6ee46c124c"
-  integrity sha512-GCSBF7iUle6rNugfURwNmCGG3Z/2+opxAMLs1nND4bhEG5PuxTIggDBoeYYSujAlLtsupzOHYJQgPS3pivwXIA==
+"@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10"
+  integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.12.13"
 
-"@babel/plugin-syntax-dynamic-import@^7.8.0", "@babel/plugin-syntax-dynamic-import@^7.8.3":
+"@babel/plugin-syntax-dynamic-import@^7.8.3":
   version "7.8.3"
   resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3"
   integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==
   dependencies:
     "@babel/helper-plugin-utils" "^7.8.0"
 
-"@babel/plugin-syntax-import-meta@^7.8.3":
+"@babel/plugin-syntax-export-namespace-from@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a"
+  integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-syntax-import-meta@^7.10.4":
   version "7.10.4"
   resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51"
   integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==
   dependencies:
     "@babel/helper-plugin-utils" "^7.10.4"
 
-"@babel/plugin-syntax-json-strings@^7.8.0":
+"@babel/plugin-syntax-json-strings@^7.8.3":
   version "7.8.3"
   resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a"
   integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==
   dependencies:
     "@babel/helper-plugin-utils" "^7.8.0"
 
-"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0", "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3":
+"@babel/plugin-syntax-logical-assignment-operators@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699"
+  integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3":
   version "7.8.3"
   resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9"
   integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==
@@ -396,359 +437,361 @@
   dependencies:
     "@babel/helper-plugin-utils" "^7.10.4"
 
-"@babel/plugin-syntax-object-rest-spread@^7.8.0":
+"@babel/plugin-syntax-object-rest-spread@^7.8.3":
   version "7.8.3"
   resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871"
   integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==
   dependencies:
     "@babel/helper-plugin-utils" "^7.8.0"
 
-"@babel/plugin-syntax-optional-catch-binding@^7.8.0":
+"@babel/plugin-syntax-optional-catch-binding@^7.8.3":
   version "7.8.3"
   resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1"
   integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==
   dependencies:
     "@babel/helper-plugin-utils" "^7.8.0"
 
-"@babel/plugin-syntax-optional-chaining@^7.8.0", "@babel/plugin-syntax-optional-chaining@^7.8.3":
+"@babel/plugin-syntax-optional-chaining@^7.8.3":
   version "7.8.3"
   resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a"
   integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==
   dependencies:
     "@babel/helper-plugin-utils" "^7.8.0"
 
-"@babel/plugin-syntax-top-level-await@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.4.tgz#4bbeb8917b54fcf768364e0a81f560e33a3ef57d"
-  integrity sha512-ni1brg4lXEmWyafKr0ccFWkJG0CeMt4WV1oyeBW6EFObF4oOHclbkj5cARxAPQyAQ2UTuplJyK4nfkXIMMFvsQ==
+"@babel/plugin-syntax-top-level-await@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.13.tgz#c5f0fa6e249f5b739727f923540cf7a806130178"
+  integrity sha512-A81F9pDwyS7yM//KwbCSDqy3Uj4NMIurtplxphWxoYtNPov7cJsDkAFNNyVlIZ3jwGycVsurZ+LtOA8gZ376iQ==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.12.13"
 
-"@babel/plugin-transform-arrow-functions@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.4.tgz#e22960d77e697c74f41c501d44d73dbf8a6a64cd"
-  integrity sha512-9J/oD1jV0ZCBcgnoFWFq1vJd4msoKb/TCpGNFyyLt0zABdcvgK3aYikZ8HjzB14c26bc7E3Q1yugpwGy2aTPNA==
+"@babel/plugin-transform-arrow-functions@^7.13.0":
+  version "7.13.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.13.0.tgz#10a59bebad52d637a027afa692e8d5ceff5e3dae"
+  integrity sha512-96lgJagobeVmazXFaDrbmCLQxBysKu7U6Do3mLsx27gf5Dk85ezysrs2BZUpXD703U/Su1xTBDxxar2oa4jAGg==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.13.0"
 
-"@babel/plugin-transform-async-to-generator@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.4.tgz#41a5017e49eb6f3cda9392a51eef29405b245a37"
-  integrity sha512-F6nREOan7J5UXTLsDsZG3DXmZSVofr2tGNwfdrVwkDWHfQckbQXnXSPfD7iO+c/2HGqycwyLST3DnZ16n+cBJQ==
+"@babel/plugin-transform-async-to-generator@^7.13.0":
+  version "7.13.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.13.0.tgz#8e112bf6771b82bf1e974e5e26806c5c99aa516f"
+  integrity sha512-3j6E004Dx0K3eGmhxVJxwwI89CTJrce7lg3UrtFuDAVQ/2+SJ/h/aSFOeE6/n0WB1GsOffsJp6MnPQNQ8nmwhg==
   dependencies:
-    "@babel/helper-module-imports" "^7.10.4"
-    "@babel/helper-plugin-utils" "^7.10.4"
-    "@babel/helper-remap-async-to-generator" "^7.10.4"
+    "@babel/helper-module-imports" "^7.12.13"
+    "@babel/helper-plugin-utils" "^7.13.0"
+    "@babel/helper-remap-async-to-generator" "^7.13.0"
 
-"@babel/plugin-transform-block-scoped-functions@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.4.tgz#1afa595744f75e43a91af73b0d998ecfe4ebc2e8"
-  integrity sha512-WzXDarQXYYfjaV1szJvN3AD7rZgZzC1JtjJZ8dMHUyiK8mxPRahynp14zzNjU3VkPqPsO38CzxiWO1c9ARZ8JA==
+"@babel/plugin-transform-block-scoped-functions@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.13.tgz#a9bf1836f2a39b4eb6cf09967739de29ea4bf4c4"
+  integrity sha512-zNyFqbc3kI/fVpqwfqkg6RvBgFpC4J18aKKMmv7KdQ/1GgREapSJAykLMVNwfRGO3BtHj3YQZl8kxCXPcVMVeg==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.12.13"
 
-"@babel/plugin-transform-block-scoping@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.10.4.tgz#a670d1364bb5019a621b9ea2001482876d734787"
-  integrity sha512-J3b5CluMg3hPUii2onJDRiaVbPtKFPLEaV5dOPY5OeAbDi1iU/UbbFFTgwb7WnanaDy7bjU35kc26W3eM5Qa0A==
+"@babel/plugin-transform-block-scoping@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.13.tgz#f36e55076d06f41dfd78557ea039c1b581642e61"
+  integrity sha512-Pxwe0iqWJX4fOOM2kEZeUuAxHMWb9nK+9oh5d11bsLoB0xMg+mkDpt0eYuDZB7ETrY9bbcVlKUGTOGWy7BHsMQ==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
-    lodash "^4.17.13"
+    "@babel/helper-plugin-utils" "^7.12.13"
 
-"@babel/plugin-transform-classes@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.4.tgz#405136af2b3e218bc4a1926228bc917ab1a0adc7"
-  integrity sha512-2oZ9qLjt161dn1ZE0Ms66xBncQH4In8Sqw1YWgBUZuGVJJS5c0OFZXL6dP2MRHrkU/eKhWg8CzFJhRQl50rQxA==
+"@babel/plugin-transform-classes@^7.13.0":
+  version "7.13.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.13.0.tgz#0265155075c42918bf4d3a4053134176ad9b533b"
+  integrity sha512-9BtHCPUARyVH1oXGcSJD3YpsqRLROJx5ZNP6tN5vnk17N0SVf9WCtf8Nuh1CFmgByKKAIMstitKduoCmsaDK5g==
   dependencies:
-    "@babel/helper-annotate-as-pure" "^7.10.4"
-    "@babel/helper-define-map" "^7.10.4"
-    "@babel/helper-function-name" "^7.10.4"
-    "@babel/helper-optimise-call-expression" "^7.10.4"
-    "@babel/helper-plugin-utils" "^7.10.4"
-    "@babel/helper-replace-supers" "^7.10.4"
-    "@babel/helper-split-export-declaration" "^7.10.4"
+    "@babel/helper-annotate-as-pure" "^7.12.13"
+    "@babel/helper-function-name" "^7.12.13"
+    "@babel/helper-optimise-call-expression" "^7.12.13"
+    "@babel/helper-plugin-utils" "^7.13.0"
+    "@babel/helper-replace-supers" "^7.13.0"
+    "@babel/helper-split-export-declaration" "^7.12.13"
     globals "^11.1.0"
 
-"@babel/plugin-transform-computed-properties@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.4.tgz#9ded83a816e82ded28d52d4b4ecbdd810cdfc0eb"
-  integrity sha512-JFwVDXcP/hM/TbyzGq3l/XWGut7p46Z3QvqFMXTfk6/09m7xZHJUN9xHfsv7vqqD4YnfI5ueYdSJtXqqBLyjBw==
+"@babel/plugin-transform-computed-properties@^7.13.0":
+  version "7.13.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.13.0.tgz#845c6e8b9bb55376b1fa0b92ef0bdc8ea06644ed"
+  integrity sha512-RRqTYTeZkZAz8WbieLTvKUEUxZlUTdmL5KGMyZj7FnMfLNKV4+r5549aORG/mgojRmFlQMJDUupwAMiF2Q7OUg==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.13.0"
 
-"@babel/plugin-transform-destructuring@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz#70ddd2b3d1bea83d01509e9bb25ddb3a74fc85e5"
-  integrity sha512-+WmfvyfsyF603iPa6825mq6Qrb7uLjTOsa3XOFzlYcYDHSS4QmpOWOL0NNBY5qMbvrcf3tq0Cw+v4lxswOBpgA==
+"@babel/plugin-transform-destructuring@^7.13.0":
+  version "7.13.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.13.0.tgz#c5dce270014d4e1ebb1d806116694c12b7028963"
+  integrity sha512-zym5em7tePoNT9s964c0/KU3JPPnuq7VhIxPRefJ4/s82cD+q1mgKfuGRDMCPL0HTyKz4dISuQlCusfgCJ86HA==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.13.0"
 
-"@babel/plugin-transform-dotall-regex@^7.10.4", "@babel/plugin-transform-dotall-regex@^7.4.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz#469c2062105c1eb6a040eaf4fac4b488078395ee"
-  integrity sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA==
+"@babel/plugin-transform-dotall-regex@^7.12.13", "@babel/plugin-transform-dotall-regex@^7.4.4":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.13.tgz#3f1601cc29905bfcb67f53910f197aeafebb25ad"
+  integrity sha512-foDrozE65ZFdUC2OfgeOCrEPTxdB3yjqxpXh8CH+ipd9CHd4s/iq81kcUpyH8ACGNEPdFqbtzfgzbT/ZGlbDeQ==
   dependencies:
-    "@babel/helper-create-regexp-features-plugin" "^7.10.4"
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-create-regexp-features-plugin" "^7.12.13"
+    "@babel/helper-plugin-utils" "^7.12.13"
 
-"@babel/plugin-transform-duplicate-keys@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.4.tgz#697e50c9fee14380fe843d1f306b295617431e47"
-  integrity sha512-GL0/fJnmgMclHiBTTWXNlYjYsA7rDrtsazHG6mglaGSTh0KsrW04qml+Bbz9FL0LcJIRwBWL5ZqlNHKTkU3xAA==
+"@babel/plugin-transform-duplicate-keys@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.13.tgz#6f06b87a8b803fd928e54b81c258f0a0033904de"
+  integrity sha512-NfADJiiHdhLBW3pulJlJI2NB0t4cci4WTZ8FtdIuNc2+8pslXdPtRRAEWqUY+m9kNOk2eRYbTAOipAxlrOcwwQ==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.12.13"
 
-"@babel/plugin-transform-exponentiation-operator@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.4.tgz#5ae338c57f8cf4001bdb35607ae66b92d665af2e"
-  integrity sha512-S5HgLVgkBcRdyQAHbKj+7KyuWx8C6t5oETmUuwz1pt3WTWJhsUV0WIIXuVvfXMxl/QQyHKlSCNNtaIamG8fysw==
+"@babel/plugin-transform-exponentiation-operator@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.13.tgz#4d52390b9a273e651e4aba6aee49ef40e80cd0a1"
+  integrity sha512-fbUelkM1apvqez/yYx1/oICVnGo2KM5s63mhGylrmXUxK/IAXSIf87QIxVfZldWf4QsOafY6vV3bX8aMHSvNrA==
   dependencies:
-    "@babel/helper-builder-binary-assignment-operator-visitor" "^7.10.4"
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-builder-binary-assignment-operator-visitor" "^7.12.13"
+    "@babel/helper-plugin-utils" "^7.12.13"
 
-"@babel/plugin-transform-for-of@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.4.tgz#c08892e8819d3a5db29031b115af511dbbfebae9"
-  integrity sha512-ItdQfAzu9AlEqmusA/65TqJ79eRcgGmpPPFvBnGILXZH975G0LNjP1yjHvGgfuCxqrPPueXOPe+FsvxmxKiHHQ==
+"@babel/plugin-transform-for-of@^7.13.0":
+  version "7.13.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.13.0.tgz#c799f881a8091ac26b54867a845c3e97d2696062"
+  integrity sha512-IHKT00mwUVYE0zzbkDgNRP6SRzvfGCYsOxIRz8KsiaaHCcT9BWIkO+H9QRJseHBLOGBZkHUdHiqj6r0POsdytg==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.13.0"
 
-"@babel/plugin-transform-function-name@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.4.tgz#6a467880e0fc9638514ba369111811ddbe2644b7"
-  integrity sha512-OcDCq2y5+E0dVD5MagT5X+yTRbcvFjDI2ZVAottGH6tzqjx/LKpgkUepu3hp/u4tZBzxxpNGwLsAvGBvQ2mJzg==
+"@babel/plugin-transform-function-name@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.13.tgz#bb024452f9aaed861d374c8e7a24252ce3a50051"
+  integrity sha512-6K7gZycG0cmIwwF7uMK/ZqeCikCGVBdyP2J5SKNCXO5EOHcqi+z7Jwf8AmyDNcBgxET8DrEtCt/mPKPyAzXyqQ==
   dependencies:
-    "@babel/helper-function-name" "^7.10.4"
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-function-name" "^7.12.13"
+    "@babel/helper-plugin-utils" "^7.12.13"
 
-"@babel/plugin-transform-literals@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.4.tgz#9f42ba0841100a135f22712d0e391c462f571f3c"
-  integrity sha512-Xd/dFSTEVuUWnyZiMu76/InZxLTYilOSr1UlHV+p115Z/Le2Fi1KXkJUYz0b42DfndostYlPub3m8ZTQlMaiqQ==
+"@babel/plugin-transform-literals@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.13.tgz#2ca45bafe4a820197cf315794a4d26560fe4bdb9"
+  integrity sha512-FW+WPjSR7hiUxMcKqyNjP05tQ2kmBCdpEpZHY1ARm96tGQCCBvXKnpjILtDplUnJ/eHZ0lALLM+d2lMFSpYJrQ==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.12.13"
 
-"@babel/plugin-transform-member-expression-literals@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.4.tgz#b1ec44fcf195afcb8db2c62cd8e551c881baf8b7"
-  integrity sha512-0bFOvPyAoTBhtcJLr9VcwZqKmSjFml1iVxvPL0ReomGU53CX53HsM4h2SzckNdkQcHox1bpAqzxBI1Y09LlBSw==
+"@babel/plugin-transform-member-expression-literals@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.13.tgz#5ffa66cd59b9e191314c9f1f803b938e8c081e40"
+  integrity sha512-kxLkOsg8yir4YeEPHLuO2tXP9R/gTjpuTOjshqSpELUN3ZAg2jfDnKUvzzJxObun38sw3wm4Uu69sX/zA7iRvg==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.12.13"
 
-"@babel/plugin-transform-modules-amd@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.4.tgz#cb407c68b862e4c1d13a2fc738c7ec5ed75fc520"
-  integrity sha512-3Fw+H3WLUrTlzi3zMiZWp3AR4xadAEMv6XRCYnd5jAlLM61Rn+CRJaZMaNvIpcJpQ3vs1kyifYvEVPFfoSkKOA==
+"@babel/plugin-transform-modules-amd@^7.13.0":
+  version "7.13.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.13.0.tgz#19f511d60e3d8753cc5a6d4e775d3a5184866cc3"
+  integrity sha512-EKy/E2NHhY/6Vw5d1k3rgoobftcNUmp9fGjb9XZwQLtTctsRBOTRO7RHHxfIky1ogMN5BxN7p9uMA3SzPfotMQ==
   dependencies:
-    "@babel/helper-module-transforms" "^7.10.4"
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-module-transforms" "^7.13.0"
+    "@babel/helper-plugin-utils" "^7.13.0"
     babel-plugin-dynamic-import-node "^2.3.3"
 
-"@babel/plugin-transform-modules-commonjs@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz#66667c3eeda1ebf7896d41f1f16b17105a2fbca0"
-  integrity sha512-Xj7Uq5o80HDLlW64rVfDBhao6OX89HKUmb+9vWYaLXBZOma4gA6tw4Ni1O5qVDoZWUV0fxMYA0aYzOawz0l+1w==
+"@babel/plugin-transform-modules-commonjs@^7.13.8":
+  version "7.13.8"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.13.8.tgz#7b01ad7c2dcf2275b06fa1781e00d13d420b3e1b"
+  integrity sha512-9QiOx4MEGglfYZ4XOnU79OHr6vIWUakIj9b4mioN8eQIoEh+pf5p/zEB36JpDFWA12nNMiRf7bfoRvl9Rn79Bw==
   dependencies:
-    "@babel/helper-module-transforms" "^7.10.4"
-    "@babel/helper-plugin-utils" "^7.10.4"
-    "@babel/helper-simple-access" "^7.10.4"
+    "@babel/helper-module-transforms" "^7.13.0"
+    "@babel/helper-plugin-utils" "^7.13.0"
+    "@babel/helper-simple-access" "^7.12.13"
     babel-plugin-dynamic-import-node "^2.3.3"
 
-"@babel/plugin-transform-modules-systemjs@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.4.tgz#8f576afd943ac2f789b35ded0a6312f929c633f9"
-  integrity sha512-Tb28LlfxrTiOTGtZFsvkjpyjCl9IoaRI52AEU/VIwOwvDQWtbNJsAqTXzh+5R7i74e/OZHH2c2w2fsOqAfnQYQ==
+"@babel/plugin-transform-modules-systemjs@^7.13.8":
+  version "7.13.8"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.13.8.tgz#6d066ee2bff3c7b3d60bf28dec169ad993831ae3"
+  integrity sha512-hwqctPYjhM6cWvVIlOIe27jCIBgHCsdH2xCJVAYQm7V5yTMoilbVMi9f6wKg0rpQAOn6ZG4AOyvCqFF/hUh6+A==
   dependencies:
-    "@babel/helper-hoist-variables" "^7.10.4"
-    "@babel/helper-module-transforms" "^7.10.4"
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-hoist-variables" "^7.13.0"
+    "@babel/helper-module-transforms" "^7.13.0"
+    "@babel/helper-plugin-utils" "^7.13.0"
+    "@babel/helper-validator-identifier" "^7.12.11"
     babel-plugin-dynamic-import-node "^2.3.3"
 
-"@babel/plugin-transform-modules-umd@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.4.tgz#9a8481fe81b824654b3a0b65da3df89f3d21839e"
-  integrity sha512-mohW5q3uAEt8T45YT7Qc5ws6mWgJAaL/8BfWD9Dodo1A3RKWli8wTS+WiQ/knF+tXlPirW/1/MqzzGfCExKECA==
+"@babel/plugin-transform-modules-umd@^7.13.0":
+  version "7.13.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.13.0.tgz#8a3d96a97d199705b9fd021580082af81c06e70b"
+  integrity sha512-D/ILzAh6uyvkWjKKyFE/W0FzWwasv6vPTSqPcjxFqn6QpX3u8DjRVliq4F2BamO2Wee/om06Vyy+vPkNrd4wxw==
   dependencies:
-    "@babel/helper-module-transforms" "^7.10.4"
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-module-transforms" "^7.13.0"
+    "@babel/helper-plugin-utils" "^7.13.0"
 
-"@babel/plugin-transform-named-capturing-groups-regex@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.10.4.tgz#78b4d978810b6f3bcf03f9e318f2fc0ed41aecb6"
-  integrity sha512-V6LuOnD31kTkxQPhKiVYzYC/Jgdq53irJC/xBSmqcNcqFGV+PER4l6rU5SH2Vl7bH9mLDHcc0+l9HUOe4RNGKA==
+"@babel/plugin-transform-named-capturing-groups-regex@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.13.tgz#2213725a5f5bbbe364b50c3ba5998c9599c5c9d9"
+  integrity sha512-Xsm8P2hr5hAxyYblrfACXpQKdQbx4m2df9/ZZSQ8MAhsadw06+jW7s9zsSw6he+mJZXRlVMyEnVktJo4zjk1WA==
   dependencies:
-    "@babel/helper-create-regexp-features-plugin" "^7.10.4"
+    "@babel/helper-create-regexp-features-plugin" "^7.12.13"
 
-"@babel/plugin-transform-new-target@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.4.tgz#9097d753cb7b024cb7381a3b2e52e9513a9c6888"
-  integrity sha512-YXwWUDAH/J6dlfwqlWsztI2Puz1NtUAubXhOPLQ5gjR/qmQ5U96DY4FQO8At33JN4XPBhrjB8I4eMmLROjjLjw==
+"@babel/plugin-transform-new-target@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.13.tgz#e22d8c3af24b150dd528cbd6e685e799bf1c351c"
+  integrity sha512-/KY2hbLxrG5GTQ9zzZSc3xWiOy379pIETEhbtzwZcw9rvuaVV4Fqy7BYGYOWZnaoXIQYbbJ0ziXLa/sKcGCYEQ==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.12.13"
 
-"@babel/plugin-transform-object-super@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.4.tgz#d7146c4d139433e7a6526f888c667e314a093894"
-  integrity sha512-5iTw0JkdRdJvr7sY0vHqTpnruUpTea32JHmq/atIWqsnNussbRzjEDyWep8UNztt1B5IusBYg8Irb0bLbiEBCQ==
+"@babel/plugin-transform-object-super@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.13.tgz#b4416a2d63b8f7be314f3d349bd55a9c1b5171f7"
+  integrity sha512-JzYIcj3XtYspZDV8j9ulnoMPZZnF/Cj0LUxPOjR89BdBVx+zYJI9MdMIlUZjbXDX+6YVeS6I3e8op+qQ3BYBoQ==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
-    "@babel/helper-replace-supers" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.12.13"
+    "@babel/helper-replace-supers" "^7.12.13"
 
-"@babel/plugin-transform-parameters@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.4.tgz#7b4d137c87ea7adc2a0f3ebf53266871daa6fced"
-  integrity sha512-RurVtZ/D5nYfEg0iVERXYKEgDFeesHrHfx8RT05Sq57ucj2eOYAP6eu5fynL4Adju4I/mP/I6SO0DqNWAXjfLQ==
+"@babel/plugin-transform-parameters@^7.13.0":
+  version "7.13.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.13.0.tgz#8fa7603e3097f9c0b7ca1a4821bc2fb52e9e5007"
+  integrity sha512-Jt8k/h/mIwE2JFEOb3lURoY5C85ETcYPnbuAJ96zRBzh1XHtQZfs62ChZ6EP22QlC8c7Xqr9q+e1SU5qttwwjw==
   dependencies:
-    "@babel/helper-get-function-arity" "^7.10.4"
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.13.0"
 
-"@babel/plugin-transform-property-literals@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.4.tgz#f6fe54b6590352298785b83edd815d214c42e3c0"
-  integrity sha512-ofsAcKiUxQ8TY4sScgsGeR2vJIsfrzqvFb9GvJ5UdXDzl+MyYCaBj/FGzXuv7qE0aJcjWMILny1epqelnFlz8g==
+"@babel/plugin-transform-property-literals@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.13.tgz#4e6a9e37864d8f1b3bc0e2dce7bf8857db8b1a81"
+  integrity sha512-nqVigwVan+lR+g8Fj8Exl0UQX2kymtjcWfMOYM1vTYEKujeyv2SkMgazf2qNcK7l4SDiKyTA/nHCPqL4e2zo1A==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.12.13"
 
-"@babel/plugin-transform-regenerator@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz#2015e59d839074e76838de2159db421966fd8b63"
-  integrity sha512-3thAHwtor39A7C04XucbMg17RcZ3Qppfxr22wYzZNcVIkPHfpM9J0SO8zuCV6SZa265kxBJSrfKTvDCYqBFXGw==
+"@babel/plugin-transform-regenerator@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.13.tgz#b628bcc9c85260ac1aeb05b45bde25210194a2f5"
+  integrity sha512-lxb2ZAvSLyJ2PEe47hoGWPmW22v7CtSl9jW8mingV4H2sEX/JOcrAj2nPuGWi56ERUm2bUpjKzONAuT6HCn2EA==
   dependencies:
     regenerator-transform "^0.14.2"
 
-"@babel/plugin-transform-reserved-words@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.4.tgz#8f2682bcdcef9ed327e1b0861585d7013f8a54dd"
-  integrity sha512-hGsw1O6Rew1fkFbDImZIEqA8GoidwTAilwCyWqLBM9f+e/u/sQMQu7uX6dyokfOayRuuVfKOW4O7HvaBWM+JlQ==
+"@babel/plugin-transform-reserved-words@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.13.tgz#7d9988d4f06e0fe697ea1d9803188aa18b472695"
+  integrity sha512-xhUPzDXxZN1QfiOy/I5tyye+TRz6lA7z6xaT4CLOjPRMVg1ldRf0LHw0TDBpYL4vG78556WuHdyO9oi5UmzZBg==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.12.13"
 
-"@babel/plugin-transform-shorthand-properties@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz#9fd25ec5cdd555bb7f473e5e6ee1c971eede4dd6"
-  integrity sha512-AC2K/t7o07KeTIxMoHneyX90v3zkm5cjHJEokrPEAGEy3UCp8sLKfnfOIGdZ194fyN4wfX/zZUWT9trJZ0qc+Q==
+"@babel/plugin-transform-shorthand-properties@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.13.tgz#db755732b70c539d504c6390d9ce90fe64aff7ad"
+  integrity sha512-xpL49pqPnLtf0tVluuqvzWIgLEhuPpZzvs2yabUHSKRNlN7ScYU7aMlmavOeyXJZKgZKQRBlh8rHbKiJDraTSw==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.12.13"
 
-"@babel/plugin-transform-spread@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.10.4.tgz#4e2c85ea0d6abaee1b24dcfbbae426fe8d674cff"
-  integrity sha512-1e/51G/Ni+7uH5gktbWv+eCED9pP8ZpRhZB3jOaI3mmzfvJTWHkuyYTv0Z5PYtyM+Tr2Ccr9kUdQxn60fI5WuQ==
+"@babel/plugin-transform-spread@^7.13.0":
+  version "7.13.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.13.0.tgz#84887710e273c1815ace7ae459f6f42a5d31d5fd"
+  integrity sha512-V6vkiXijjzYeFmQTr3dBxPtZYLPcUfY34DebOU27jIl2M/Y8Egm52Hw82CSjjPqd54GTlJs5x+CR7HeNr24ckg==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.13.0"
+    "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1"
 
-"@babel/plugin-transform-sticky-regex@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.4.tgz#8f3889ee8657581130a29d9cc91d7c73b7c4a28d"
-  integrity sha512-Ddy3QZfIbEV0VYcVtFDCjeE4xwVTJWTmUtorAJkn6u/92Z/nWJNV+mILyqHKrUxXYKA2EoCilgoPePymKL4DvQ==
+"@babel/plugin-transform-sticky-regex@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.13.tgz#760ffd936face73f860ae646fb86ee82f3d06d1f"
+  integrity sha512-Jc3JSaaWT8+fr7GRvQP02fKDsYk4K/lYwWq38r/UGfaxo89ajud321NH28KRQ7xy1Ybc0VUE5Pz8psjNNDUglg==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
-    "@babel/helper-regex" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.12.13"
 
-"@babel/plugin-transform-template-literals@^7.10.4", "@babel/plugin-transform-template-literals@^7.8.3":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.4.tgz#e6375407b30fcb7fcfdbba3bb98ef3e9d36df7bc"
-  integrity sha512-4NErciJkAYe+xI5cqfS8pV/0ntlY5N5Ske/4ImxAVX7mk9Rxt2bwDTGv1Msc2BRJvWQcmYEC+yoMLdX22aE4VQ==
+"@babel/plugin-transform-template-literals@^7.13.0", "@babel/plugin-transform-template-literals@^7.8.3":
+  version "7.13.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.13.0.tgz#a36049127977ad94438dee7443598d1cefdf409d"
+  integrity sha512-d67umW6nlfmr1iehCcBv69eSUSySk1EsIS8aTDX4Xo9qajAh6mYtcl4kJrBkGXuxZPEgVr7RVfAvNW6YQkd4Mw==
   dependencies:
-    "@babel/helper-annotate-as-pure" "^7.10.4"
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.13.0"
 
-"@babel/plugin-transform-typeof-symbol@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.4.tgz#9509f1a7eec31c4edbffe137c16cc33ff0bc5bfc"
-  integrity sha512-QqNgYwuuW0y0H+kUE/GWSR45t/ccRhe14Fs/4ZRouNNQsyd4o3PG4OtHiIrepbM2WKUBDAXKCAK/Lk4VhzTaGA==
+"@babel/plugin-transform-typeof-symbol@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.13.tgz#785dd67a1f2ea579d9c2be722de8c84cb85f5a7f"
+  integrity sha512-eKv/LmUJpMnu4npgfvs3LiHhJua5fo/CysENxa45YCQXZwKnGCQKAg87bvoqSW1fFT+HA32l03Qxsm8ouTY3ZQ==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.12.13"
 
-"@babel/plugin-transform-unicode-escapes@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.4.tgz#feae523391c7651ddac115dae0a9d06857892007"
-  integrity sha512-y5XJ9waMti2J+e7ij20e+aH+fho7Wb7W8rNuu72aKRwCHFqQdhkdU2lo3uZ9tQuboEJcUFayXdARhcxLQ3+6Fg==
+"@babel/plugin-transform-unicode-escapes@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.13.tgz#840ced3b816d3b5127dd1d12dcedc5dead1a5e74"
+  integrity sha512-0bHEkdwJ/sN/ikBHfSmOXPypN/beiGqjo+o4/5K+vxEFNPRPdImhviPakMKG4x96l85emoa0Z6cDflsdBusZbw==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.12.13"
 
-"@babel/plugin-transform-unicode-regex@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.10.4.tgz#e56d71f9282fac6db09c82742055576d5e6d80a8"
-  integrity sha512-wNfsc4s8N2qnIwpO/WP2ZiSyjfpTamT2C9V9FDH/Ljub9zw6P3SjkXcFmc0RQUt96k2fmIvtla2MMjgTwIAC+A==
+"@babel/plugin-transform-unicode-regex@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.13.tgz#b52521685804e155b1202e83fc188d34bb70f5ac"
+  integrity sha512-mDRzSNY7/zopwisPZ5kM9XKCfhchqIYwAKRERtEnhYscZB79VRekuRSoYbN0+KVe3y8+q1h6A4svXtP7N+UoCA==
   dependencies:
-    "@babel/helper-create-regexp-features-plugin" "^7.10.4"
-    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-create-regexp-features-plugin" "^7.12.13"
+    "@babel/helper-plugin-utils" "^7.12.13"
 
 "@babel/preset-env@^7.9.0":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.10.4.tgz#fbf57f9a803afd97f4f32e4f798bb62e4b2bef5f"
-  integrity sha512-tcmuQ6vupfMZPrLrc38d0sF2OjLT3/bZ0dry5HchNCQbrokoQi4reXqclvkkAT5b+gWc23meVWpve5P/7+w/zw==
+  version "7.13.12"
+  resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.13.12.tgz#6dff470478290582ac282fb77780eadf32480237"
+  integrity sha512-JzElc6jk3Ko6zuZgBtjOd01pf9yYDEIH8BcqVuYIuOkzOwDesoa/Nz4gIo4lBG6K861KTV9TvIgmFuT6ytOaAA==
   dependencies:
-    "@babel/compat-data" "^7.10.4"
-    "@babel/helper-compilation-targets" "^7.10.4"
-    "@babel/helper-module-imports" "^7.10.4"
-    "@babel/helper-plugin-utils" "^7.10.4"
-    "@babel/plugin-proposal-async-generator-functions" "^7.10.4"
-    "@babel/plugin-proposal-class-properties" "^7.10.4"
-    "@babel/plugin-proposal-dynamic-import" "^7.10.4"
-    "@babel/plugin-proposal-json-strings" "^7.10.4"
-    "@babel/plugin-proposal-nullish-coalescing-operator" "^7.10.4"
-    "@babel/plugin-proposal-numeric-separator" "^7.10.4"
-    "@babel/plugin-proposal-object-rest-spread" "^7.10.4"
-    "@babel/plugin-proposal-optional-catch-binding" "^7.10.4"
-    "@babel/plugin-proposal-optional-chaining" "^7.10.4"
-    "@babel/plugin-proposal-private-methods" "^7.10.4"
-    "@babel/plugin-proposal-unicode-property-regex" "^7.10.4"
-    "@babel/plugin-syntax-async-generators" "^7.8.0"
-    "@babel/plugin-syntax-class-properties" "^7.10.4"
-    "@babel/plugin-syntax-dynamic-import" "^7.8.0"
-    "@babel/plugin-syntax-json-strings" "^7.8.0"
-    "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0"
+    "@babel/compat-data" "^7.13.12"
+    "@babel/helper-compilation-targets" "^7.13.10"
+    "@babel/helper-plugin-utils" "^7.13.0"
+    "@babel/helper-validator-option" "^7.12.17"
+    "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.13.12"
+    "@babel/plugin-proposal-async-generator-functions" "^7.13.8"
+    "@babel/plugin-proposal-class-properties" "^7.13.0"
+    "@babel/plugin-proposal-dynamic-import" "^7.13.8"
+    "@babel/plugin-proposal-export-namespace-from" "^7.12.13"
+    "@babel/plugin-proposal-json-strings" "^7.13.8"
+    "@babel/plugin-proposal-logical-assignment-operators" "^7.13.8"
+    "@babel/plugin-proposal-nullish-coalescing-operator" "^7.13.8"
+    "@babel/plugin-proposal-numeric-separator" "^7.12.13"
+    "@babel/plugin-proposal-object-rest-spread" "^7.13.8"
+    "@babel/plugin-proposal-optional-catch-binding" "^7.13.8"
+    "@babel/plugin-proposal-optional-chaining" "^7.13.12"
+    "@babel/plugin-proposal-private-methods" "^7.13.0"
+    "@babel/plugin-proposal-unicode-property-regex" "^7.12.13"
+    "@babel/plugin-syntax-async-generators" "^7.8.4"
+    "@babel/plugin-syntax-class-properties" "^7.12.13"
+    "@babel/plugin-syntax-dynamic-import" "^7.8.3"
+    "@babel/plugin-syntax-export-namespace-from" "^7.8.3"
+    "@babel/plugin-syntax-json-strings" "^7.8.3"
+    "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4"
+    "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
     "@babel/plugin-syntax-numeric-separator" "^7.10.4"
-    "@babel/plugin-syntax-object-rest-spread" "^7.8.0"
-    "@babel/plugin-syntax-optional-catch-binding" "^7.8.0"
-    "@babel/plugin-syntax-optional-chaining" "^7.8.0"
-    "@babel/plugin-syntax-top-level-await" "^7.10.4"
-    "@babel/plugin-transform-arrow-functions" "^7.10.4"
-    "@babel/plugin-transform-async-to-generator" "^7.10.4"
-    "@babel/plugin-transform-block-scoped-functions" "^7.10.4"
-    "@babel/plugin-transform-block-scoping" "^7.10.4"
-    "@babel/plugin-transform-classes" "^7.10.4"
-    "@babel/plugin-transform-computed-properties" "^7.10.4"
-    "@babel/plugin-transform-destructuring" "^7.10.4"
-    "@babel/plugin-transform-dotall-regex" "^7.10.4"
-    "@babel/plugin-transform-duplicate-keys" "^7.10.4"
-    "@babel/plugin-transform-exponentiation-operator" "^7.10.4"
-    "@babel/plugin-transform-for-of" "^7.10.4"
-    "@babel/plugin-transform-function-name" "^7.10.4"
-    "@babel/plugin-transform-literals" "^7.10.4"
-    "@babel/plugin-transform-member-expression-literals" "^7.10.4"
-    "@babel/plugin-transform-modules-amd" "^7.10.4"
-    "@babel/plugin-transform-modules-commonjs" "^7.10.4"
-    "@babel/plugin-transform-modules-systemjs" "^7.10.4"
-    "@babel/plugin-transform-modules-umd" "^7.10.4"
-    "@babel/plugin-transform-named-capturing-groups-regex" "^7.10.4"
-    "@babel/plugin-transform-new-target" "^7.10.4"
-    "@babel/plugin-transform-object-super" "^7.10.4"
-    "@babel/plugin-transform-parameters" "^7.10.4"
-    "@babel/plugin-transform-property-literals" "^7.10.4"
-    "@babel/plugin-transform-regenerator" "^7.10.4"
-    "@babel/plugin-transform-reserved-words" "^7.10.4"
-    "@babel/plugin-transform-shorthand-properties" "^7.10.4"
-    "@babel/plugin-transform-spread" "^7.10.4"
-    "@babel/plugin-transform-sticky-regex" "^7.10.4"
-    "@babel/plugin-transform-template-literals" "^7.10.4"
-    "@babel/plugin-transform-typeof-symbol" "^7.10.4"
-    "@babel/plugin-transform-unicode-escapes" "^7.10.4"
-    "@babel/plugin-transform-unicode-regex" "^7.10.4"
-    "@babel/preset-modules" "^0.1.3"
-    "@babel/types" "^7.10.4"
-    browserslist "^4.12.0"
-    core-js-compat "^3.6.2"
-    invariant "^2.2.2"
-    levenary "^1.1.1"
-    semver "^5.5.0"
+    "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
+    "@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
+    "@babel/plugin-syntax-optional-chaining" "^7.8.3"
+    "@babel/plugin-syntax-top-level-await" "^7.12.13"
+    "@babel/plugin-transform-arrow-functions" "^7.13.0"
+    "@babel/plugin-transform-async-to-generator" "^7.13.0"
+    "@babel/plugin-transform-block-scoped-functions" "^7.12.13"
+    "@babel/plugin-transform-block-scoping" "^7.12.13"
+    "@babel/plugin-transform-classes" "^7.13.0"
+    "@babel/plugin-transform-computed-properties" "^7.13.0"
+    "@babel/plugin-transform-destructuring" "^7.13.0"
+    "@babel/plugin-transform-dotall-regex" "^7.12.13"
+    "@babel/plugin-transform-duplicate-keys" "^7.12.13"
+    "@babel/plugin-transform-exponentiation-operator" "^7.12.13"
+    "@babel/plugin-transform-for-of" "^7.13.0"
+    "@babel/plugin-transform-function-name" "^7.12.13"
+    "@babel/plugin-transform-literals" "^7.12.13"
+    "@babel/plugin-transform-member-expression-literals" "^7.12.13"
+    "@babel/plugin-transform-modules-amd" "^7.13.0"
+    "@babel/plugin-transform-modules-commonjs" "^7.13.8"
+    "@babel/plugin-transform-modules-systemjs" "^7.13.8"
+    "@babel/plugin-transform-modules-umd" "^7.13.0"
+    "@babel/plugin-transform-named-capturing-groups-regex" "^7.12.13"
+    "@babel/plugin-transform-new-target" "^7.12.13"
+    "@babel/plugin-transform-object-super" "^7.12.13"
+    "@babel/plugin-transform-parameters" "^7.13.0"
+    "@babel/plugin-transform-property-literals" "^7.12.13"
+    "@babel/plugin-transform-regenerator" "^7.12.13"
+    "@babel/plugin-transform-reserved-words" "^7.12.13"
+    "@babel/plugin-transform-shorthand-properties" "^7.12.13"
+    "@babel/plugin-transform-spread" "^7.13.0"
+    "@babel/plugin-transform-sticky-regex" "^7.12.13"
+    "@babel/plugin-transform-template-literals" "^7.13.0"
+    "@babel/plugin-transform-typeof-symbol" "^7.12.13"
+    "@babel/plugin-transform-unicode-escapes" "^7.12.13"
+    "@babel/plugin-transform-unicode-regex" "^7.12.13"
+    "@babel/preset-modules" "^0.1.4"
+    "@babel/types" "^7.13.12"
+    babel-plugin-polyfill-corejs2 "^0.1.4"
+    babel-plugin-polyfill-corejs3 "^0.1.3"
+    babel-plugin-polyfill-regenerator "^0.1.2"
+    core-js-compat "^3.9.0"
+    semver "^6.3.0"
 
-"@babel/preset-modules@^0.1.3":
-  version "0.1.3"
-  resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.3.tgz#13242b53b5ef8c883c3cf7dddd55b36ce80fbc72"
-  integrity sha512-Ra3JXOHBq2xd56xSF7lMKXdjBn3T772Y1Wet3yWnkDly9zHvJki029tAFzvAAK5cf4YV3yoxuP61crYRol6SVg==
+"@babel/preset-modules@^0.1.4":
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.4.tgz#362f2b68c662842970fdb5e254ffc8fc1c2e415e"
+  integrity sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==
   dependencies:
     "@babel/helper-plugin-utils" "^7.0.0"
     "@babel/plugin-proposal-unicode-property-regex" "^7.4.4"
@@ -757,43 +800,42 @@
     esutils "^2.0.2"
 
 "@babel/runtime@^7.8.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.4.tgz#a6724f1a6b8d2f6ea5236dbfe58c7d7ea9c5eb99"
-  integrity sha512-UpTN5yUJr9b4EX2CnGNWIvER7Ab83ibv0pcvvHc4UOdrBI5jb8bj+32cCwPX6xu0mt2daFNjYhoi+X7beH0RSw==
+  version "7.13.10"
+  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.13.10.tgz#47d42a57b6095f4468da440388fdbad8bebf0d7d"
+  integrity sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==
   dependencies:
     regenerator-runtime "^0.13.4"
 
-"@babel/template@^7.10.4", "@babel/template@^7.4.0":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278"
-  integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==
+"@babel/template@^7.12.13", "@babel/template@^7.4.0":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.13.tgz#530265be8a2589dbb37523844c5bcb55947fb327"
+  integrity sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==
   dependencies:
-    "@babel/code-frame" "^7.10.4"
-    "@babel/parser" "^7.10.4"
-    "@babel/types" "^7.10.4"
+    "@babel/code-frame" "^7.12.13"
+    "@babel/parser" "^7.12.13"
+    "@babel/types" "^7.12.13"
 
-"@babel/traverse@^7.10.4", "@babel/traverse@^7.4.3":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.10.4.tgz#e642e5395a3b09cc95c8e74a27432b484b697818"
-  integrity sha512-aSy7p5THgSYm4YyxNGz6jZpXf+Ok40QF3aA2LyIONkDHpAcJzDUqlCKXv6peqYUs2gmic849C/t2HKw2a2K20Q==
+"@babel/traverse@^7.13.0", "@babel/traverse@^7.13.13", "@babel/traverse@^7.4.3":
+  version "7.13.13"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.13.13.tgz#39aa9c21aab69f74d948a486dd28a2dbdbf5114d"
+  integrity sha512-CblEcwmXKR6eP43oQGG++0QMTtCjAsa3frUuzHoiIJWpaIIi8dwMyEFUJoXRLxagGqCK+jALRwIO+o3R9p/uUg==
   dependencies:
-    "@babel/code-frame" "^7.10.4"
-    "@babel/generator" "^7.10.4"
-    "@babel/helper-function-name" "^7.10.4"
-    "@babel/helper-split-export-declaration" "^7.10.4"
-    "@babel/parser" "^7.10.4"
-    "@babel/types" "^7.10.4"
+    "@babel/code-frame" "^7.12.13"
+    "@babel/generator" "^7.13.9"
+    "@babel/helper-function-name" "^7.12.13"
+    "@babel/helper-split-export-declaration" "^7.12.13"
+    "@babel/parser" "^7.13.13"
+    "@babel/types" "^7.13.13"
     debug "^4.1.0"
     globals "^11.1.0"
-    lodash "^4.17.13"
 
-"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.4.tgz#369517188352e18219981efd156bfdb199fff1ee"
-  integrity sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg==
+"@babel/types@^7.0.0", "@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.13.0", "@babel/types@^7.13.12", "@babel/types@^7.13.13", "@babel/types@^7.13.14", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4":
+  version "7.13.14"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.14.tgz#c35a4abb15c7cd45a2746d78ab328e362cbace0d"
+  integrity sha512-A2aa3QTkWoyqsZZFl56MLUsfmh7O0gN41IPvXAE/++8ojpbz12SszD7JEGYVdn4f9Kt4amIei07swF1h4AqmmQ==
   dependencies:
-    "@babel/helper-validator-identifier" "^7.10.4"
-    lodash "^4.17.13"
+    "@babel/helper-validator-identifier" "^7.12.11"
+    lodash "^4.17.19"
     to-fast-properties "^2.0.0"
 
 "@koa/cors@^3.1.0":
@@ -803,48 +845,48 @@
   dependencies:
     vary "^1.1.2"
 
-"@open-wc/building-utils@^2.18.0":
-  version "2.18.0"
-  resolved "https://registry.yarnpkg.com/@open-wc/building-utils/-/building-utils-2.18.0.tgz#f80929dfcfb6d8a6cb5c933654c721808b4bb2d3"
-  integrity sha512-U1n8sLQlLt3IuqhU7tDsGQAGUfVMiB64xJsAmJEtekposrjqkjtRLU/WipvROl1A2GTsrMojMjNbFqzJghpd6g==
+"@open-wc/building-utils@^2.18.0", "@open-wc/building-utils@^2.18.3":
+  version "2.18.4"
+  resolved "https://registry.yarnpkg.com/@open-wc/building-utils/-/building-utils-2.18.4.tgz#397e42039f5d26c38f7a2cc01e347e0e5c2e8e99"
+  integrity sha512-wjNp9oE1SFsiBEqaI67ff60KHDpDbGMNF+82pvCHe412SFY4q8DNy8A+hesj1nZsuZHH1/olDfzBDbYKAnmgMg==
   dependencies:
-    "@babel/core" "^7.9.0"
+    "@babel/core" "^7.11.1"
     "@babel/plugin-syntax-dynamic-import" "^7.8.3"
-    "@webcomponents/shadycss" "^1.9.4"
-    "@webcomponents/webcomponentsjs" "^2.4.0"
+    "@webcomponents/shadycss" "^1.10.2"
+    "@webcomponents/webcomponentsjs" "^2.5.0"
     arrify "^2.0.1"
-    browserslist "^4.9.1"
-    chokidar "^3.0.0"
-    clean-css "^4.2.1"
+    browserslist "^4.16.0"
+    chokidar "^3.4.3"
+    clean-css "^4.2.3"
     clone "^2.1.2"
-    core-js-bundle "^3.6.0"
+    core-js-bundle "^3.8.1"
     deepmerge "^4.2.2"
-    es-module-shims "^0.4.6"
-    html-minifier "^4.0.0"
+    es-module-shims "^0.4.7"
+    html-minifier-terser "^5.1.1"
     lru-cache "^5.1.1"
     minimatch "^3.0.4"
     parse5 "^5.1.1"
     path-is-inside "^1.0.2"
-    regenerator-runtime "^0.13.3"
-    resolve "^1.11.1"
+    regenerator-runtime "^0.13.7"
+    resolve "^1.19.0"
     rimraf "^3.0.2"
     shady-css-scoped-element "^0.0.2"
-    systemjs "^6.3.1"
+    systemjs "^6.8.3"
     terser "^4.6.7"
     valid-url "^1.0.9"
-    whatwg-fetch "^3.0.0"
-    whatwg-url "^7.0.0"
+    whatwg-fetch "^3.5.0"
+    whatwg-url "^7.1.0"
 
 "@open-wc/karma-esm@^2.16.16":
-  version "2.16.16"
-  resolved "https://registry.yarnpkg.com/@open-wc/karma-esm/-/karma-esm-2.16.16.tgz#6ebff57f249e95f777b7e04782ef08ed41e22f53"
-  integrity sha512-IALT10JfwK+h7T0hGKTUliGdkWzQbyQg195D+RfUteIoTof6Z5+dBp7JUh2fQygIyNj7IIYHJ9ej816QlgHjdA==
+  version "2.16.18"
+  resolved "https://registry.yarnpkg.com/@open-wc/karma-esm/-/karma-esm-2.16.18.tgz#01f3f8c694d7b8dd3aef3159659f3fa9d3090c44"
+  integrity sha512-K+HeXqRdvOupnlRr7rHgBFSqgyr5E0KNS89BTnHN0qKcDpa+M+m1sZHInPrB+iFqLQ7hhWNeGmtesDFfnIBhaQ==
   dependencies:
     "@open-wc/building-utils" "^2.18.0"
     babel-plugin-istanbul "^5.1.4"
     chokidar "^3.0.0"
     deepmerge "^4.2.2"
-    es-dev-server "^1.56.0"
+    es-dev-server "^1.57.0"
     minimatch "^3.0.4"
     node-fetch "^2.6.0"
     polyfills-loader "^1.6.1"
@@ -859,9 +901,9 @@
     "@polymer/polymer" "^3.0.0"
 
 "@polymer/polymer@^3.0.0":
-  version "3.3.1"
-  resolved "https://registry.yarnpkg.com/@polymer/polymer/-/polymer-3.3.1.tgz#9ad48992d2a96775f80b0673f3a615d6df8a3dfc"
-  integrity sha512-8KaB48tzyMjdsHdxo5KvCAaqmTe7rYDzQAoj/pyEfq9Fp4YfUaS+/xqwYj0GbiDAUNzwkmEQ7dw9cgnRNdKO8A==
+  version "3.4.1"
+  resolved "https://registry.yarnpkg.com/@polymer/polymer/-/polymer-3.4.1.tgz#333bef25711f8411bb5624fb3eba8212ef8bee96"
+  integrity sha512-KPWnhDZibtqKrUz7enIPOiO4ZQoJNOuLwqrhV2MXzIt3VVnUVJVG5ORz4Z2sgO+UZ+/UZnPD0jqY+jmw/+a9mQ==
   dependencies:
     "@webcomponents/shadycss" "^1.9.1"
 
@@ -890,10 +932,10 @@
     estree-walker "^1.0.1"
     picomatch "^2.2.2"
 
-"@sinonjs/commons@^1", "@sinonjs/commons@^1.6.0", "@sinonjs/commons@^1.7.0", "@sinonjs/commons@^1.7.2":
-  version "1.8.0"
-  resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.0.tgz#c8d68821a854c555bba172f3b06959a0039b236d"
-  integrity sha512-wEj54PfsZ5jGSwMX68G8ZXFawcSglQSXqCftWX3ec8MDUzQdHgcKvw97awHbY0efQEL5iKUOAmmVtoYgmrSG4Q==
+"@sinonjs/commons@^1.6.0", "@sinonjs/commons@^1.7.0", "@sinonjs/commons@^1.8.1":
+  version "1.8.2"
+  resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.2.tgz#858f5c4b48d80778fde4b9d541f27edc0d56488b"
+  integrity sha512-sruwd86RJHdsVf/AtBoijDmUqJp3B6hF/DGC23C+JaegnDHaZyewCjoVGTdg3J0uz3Zs7NnIT05OBOmML72lQw==
   dependencies:
     type-detect "4.0.8"
 
@@ -904,18 +946,17 @@
   dependencies:
     "@sinonjs/commons" "^1.7.0"
 
-"@sinonjs/formatio@^5.0.1":
-  version "5.0.1"
-  resolved "https://registry.yarnpkg.com/@sinonjs/formatio/-/formatio-5.0.1.tgz#f13e713cb3313b1ab965901b01b0828ea6b77089"
-  integrity sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==
+"@sinonjs/fake-timers@^7.0.4":
+  version "7.0.5"
+  resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-7.0.5.tgz#558a7f8145a01366c44b3dcbdd7172c05c461564"
+  integrity sha512-fUt6b15bjV/VW93UP5opNXJxdwZSbK1EdiwnhN7XrQrcpaOhMJpZ/CjwFpM3THpxwA+YviBUJKSuEqKlCK5alw==
   dependencies:
-    "@sinonjs/commons" "^1"
-    "@sinonjs/samsam" "^5.0.2"
+    "@sinonjs/commons" "^1.7.0"
 
-"@sinonjs/samsam@^5.0.2", "@sinonjs/samsam@^5.0.3":
-  version "5.0.3"
-  resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-5.0.3.tgz#86f21bdb3d52480faf0892a480c9906aa5a52938"
-  integrity sha512-QucHkc2uMJ0pFGjJUDP3F9dq5dx8QIaqISl9QgwLOh6P9yv877uONPGXh/OH/0zmM3tW1JjuJltAZV2l7zU+uQ==
+"@sinonjs/samsam@^5.3.1":
+  version "5.3.1"
+  resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-5.3.1.tgz#375a45fe6ed4e92fca2fb920e007c48232a6507f"
+  integrity sha512-1Hc0b1TtyfBu8ixF/tpfSHTVWKwCBLY4QJbkgnE7HcwyvT2xArDxb4K7dMgqRm3szI+LJbzmW/s4xxEhv6hwDg==
   dependencies:
     "@sinonjs/commons" "^1.6.0"
     lodash.get "^4.4.2"
@@ -934,9 +975,9 @@
     "@types/node" "*"
 
 "@types/babel__core@^7.1.3":
-  version "7.1.9"
-  resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.9.tgz#77e59d438522a6fb898fa43dc3455c6e72f3963d"
-  integrity sha512-sY2RsIJ5rpER1u3/aQ8OFSI7qGIy8o1NEEbgb2UaJcvOtXOMpd39ko723NBpjQFg9SIX7TXtjejZVGeIMLhoOw==
+  version "7.1.14"
+  resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.14.tgz#faaeefc4185ec71c389f4501ee5ec84b170cc402"
+  integrity sha512-zGZJzzBUVDo/eV6KgbE0f0ZI7dInEYvo12Rb70uNQDshC3SkRMb67ja0GgRHZgAX3Za6rhaWlvbDO8rrGyAb1g==
   dependencies:
     "@babel/parser" "^7.1.0"
     "@babel/types" "^7.0.0"
@@ -945,24 +986,24 @@
     "@types/babel__traverse" "*"
 
 "@types/babel__generator@*":
-  version "7.6.1"
-  resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.1.tgz#4901767b397e8711aeb99df8d396d7ba7b7f0e04"
-  integrity sha512-bBKm+2VPJcMRVwNhxKu8W+5/zT7pwNEqeokFOmbvVSqGzFneNxYcEBro9Ac7/N9tlsaPYnZLK8J1LWKkMsLAew==
+  version "7.6.2"
+  resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.2.tgz#f3d71178e187858f7c45e30380f8f1b7415a12d8"
+  integrity sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==
   dependencies:
     "@babel/types" "^7.0.0"
 
 "@types/babel__template@*":
-  version "7.0.2"
-  resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.0.2.tgz#4ff63d6b52eddac1de7b975a5223ed32ecea9307"
-  integrity sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==
+  version "7.4.0"
+  resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.0.tgz#0c888dd70b3ee9eebb6e4f200e809da0076262be"
+  integrity sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==
   dependencies:
     "@babel/parser" "^7.1.0"
     "@babel/types" "^7.0.0"
 
 "@types/babel__traverse@*":
-  version "7.0.12"
-  resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.0.12.tgz#22f49a028e69465390f87bb103ebd61bd086b8f5"
-  integrity sha512-t4CoEokHTfcyfb4hUaF9oOHu9RmmNWnm1CP0YmMqOOfClKascOmvlEM736vlqeScuGvBDsHkf8R2INd4DWreQA==
+  version "7.11.1"
+  resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.11.1.tgz#654f6c4f67568e24c23b367e947098c6206fa639"
+  integrity sha512-Vs0hm0vPahPMYi9tDjtP66llufgO3ST16WXaSTtDGEl9cewAl3AibmxWw6TINOqHPT9z0uABKAYjT9jNSg4npw==
   dependencies:
     "@babel/types" "^7.3.0"
 
@@ -975,24 +1016,26 @@
     "@types/node" "*"
 
 "@types/browserslist-useragent@^3.0.0":
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/@types/browserslist-useragent/-/browserslist-useragent-3.0.0.tgz#d425c9818182ce71ce53866798cee9c7d41d6e53"
-  integrity sha512-ZBvKzg3yyWNYEkwxAzdmUzp27sFvw+1m080/+2lwrt+eltNefn1f4fnpMyrjOla31p8zLleCYqQXw+3EETfn0w==
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/@types/browserslist-useragent/-/browserslist-useragent-3.0.2.tgz#e4d9a5b3949f7291c0a253e3b9e092e66673114c"
+  integrity sha512-Y2McxEf2m89AgMYgp/E33pxH0DKYHpCHhSSBlPTATnEVatWmHMyWRQpdlOK+BrwcFK62+A+P3mu0s1Owkas9zw==
 
 "@types/browserslist@^4.8.0":
-  version "4.8.0"
-  resolved "https://registry.yarnpkg.com/@types/browserslist/-/browserslist-4.8.0.tgz#60489aefdf0fcb56c2d8eb65267ff08dad7a526d"
-  integrity sha512-4PyO9OM08APvxxo1NmQyQKlJdowPCOQIy5D/NLO3aO0vGC57wsMptvGp3b8IbYnupFZr92l1dlVief1JvS6STQ==
+  version "4.15.0"
+  resolved "https://registry.yarnpkg.com/@types/browserslist/-/browserslist-4.15.0.tgz#ba0265b33003a2581df1fc5f483321a30205f2d2"
+  integrity sha512-h9LyKErRGZqMsHh9bd+FE8yCIal4S0DxKTOeui56VgVXqa66TKiuaIUxCAI7c1O0LjaUzOTcsMyOpO9GetozRA==
+  dependencies:
+    browserslist "*"
 
 "@types/caniuse-api@^3.0.0":
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/@types/caniuse-api/-/caniuse-api-3.0.0.tgz#af31cc52062be0ab24583be072fd49b634dcc2fe"
-  integrity sha512-wT1VfnScjAftZsvLYaefu/UuwYJdYBwD2JDL2OQd01plGmuAoir5V6HnVHgrfh7zEwcasoiyO2wQ+W58sNh2sw==
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@types/caniuse-api/-/caniuse-api-3.0.1.tgz#94c0073a2c305d0476ce9199cd6ef3fd7d2c5f66"
+  integrity sha512-VcjPciJLx86btwWypSo6vRzZSOC6asS3/SGgn7r7Xk7jAWNyMoxCy+IQzI2vuW2Bvs3iytyOEwsjLJKmHXBvmA==
 
-"@types/chai@^4.2.14":
-  version "4.2.14"
-  resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.14.tgz#44d2dd0b5de6185089375d976b4ec5caf6861193"
-  integrity sha512-G+ITQPXkwTrslfG5L/BksmbLUA0M1iybEsmCWPqzSxsRRhJZimBKJkoMi8fr/CPygPTj4zO5pJH7I2/cm9M7SQ==
+"@types/chai@^4.2.16":
+  version "4.2.16"
+  resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.16.tgz#f09cc36e18d28274f942e7201147cce34d97e8c8"
+  integrity sha512-vI5iOAsez9+roLS3M3+Xx7w+WRuDtSmF8bQkrbcIJ2sC1PcDgVoA0WGpa+bIrJ+y8zqY2oi//fUctkxtIcXJCw==
 
 "@types/command-line-args@^5.0.0":
   version "5.0.0"
@@ -1005,9 +1048,9 @@
   integrity sha512-/xUgezxxYePeXhg5S04hUjxG9JZi+rJTs1+4NwpYPfSaS7BeDa6tVJkH6lN9Cb6rl8d24Fi2uX0s0Ngg2JT6gg==
 
 "@types/connect@*":
-  version "3.4.33"
-  resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.33.tgz#31610c901eca573b8713c3330abc6e6b9f588546"
-  integrity sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==
+  version "3.4.34"
+  resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.34.tgz#170a40223a6d666006d93ca128af2beb1d9b1901"
+  integrity sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==
   dependencies:
     "@types/node" "*"
 
@@ -1017,9 +1060,9 @@
   integrity sha512-P1bffQfhD3O4LW0ioENXUhZ9OIa0Zn+P7M+pWgkCKaT53wVLSq0mrKksCID/FGHpFhRSxRGhgrQmfhRuzwtKdg==
 
 "@types/cookies@*":
-  version "0.7.4"
-  resolved "https://registry.yarnpkg.com/@types/cookies/-/cookies-0.7.4.tgz#26dedf791701abc0e36b5b79a5722f40e455f87b"
-  integrity sha512-oTGtMzZZAVuEjTwCjIh8T8FrC8n/uwy+PG0yTvQcdZ7etoel7C7/3MSd7qrukENTgQtotG7gvBlBojuVs7X5rw==
+  version "0.7.6"
+  resolved "https://registry.yarnpkg.com/@types/cookies/-/cookies-0.7.6.tgz#71212c5391a976d3bae57d4b09fac20fc6bda504"
+  integrity sha512-FK4U5Qyn7/Sc5ih233OuHO0qAkOpEcD/eG6584yEiLKizTFRny86qHLe/rej3HFQrkBuUjF4whFliAdODbVN/w==
   dependencies:
     "@types/connect" "*"
     "@types/express" "*"
@@ -1043,22 +1086,22 @@
   dependencies:
     "@types/node" "*"
 
-"@types/express-serve-static-core@*":
-  version "4.17.8"
-  resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.8.tgz#b8f7b714138536742da222839892e203df569d1c"
-  integrity sha512-1SJZ+R3Q/7mLkOD9ewCBDYD2k0WyZQtWYqF/2VvoNN2/uhI49J9CDN4OAm+wGMA0DbArA4ef27xl4+JwMtGggw==
+"@types/express-serve-static-core@^4.17.18":
+  version "4.17.19"
+  resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.19.tgz#00acfc1632e729acac4f1530e9e16f6dd1508a1d"
+  integrity sha512-DJOSHzX7pCiSElWaGR8kCprwibCB/3yW6vcT8VG3P0SJjnv19gnWG/AZMfM60Xj/YJIp/YCaDHyvzsFVeniARA==
   dependencies:
     "@types/node" "*"
     "@types/qs" "*"
     "@types/range-parser" "*"
 
 "@types/express@*":
-  version "4.17.6"
-  resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.6.tgz#6bce49e49570507b86ea1b07b806f04697fac45e"
-  integrity sha512-n/mr9tZI83kd4azlPG5y997C/M4DNABK9yErhFM6hKdym4kkmd9j0vtsJyjFIwfRBxtrxZtAfGZCNRIBMFLK5w==
+  version "4.17.11"
+  resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.11.tgz#debe3caa6f8e5fcda96b47bd54e2f40c4ee59545"
+  integrity sha512-no+R6rW60JEc59977wIxreQVsIEOAYwgCqldrA/vkpCnbD7MqTefO97lmoBe4WE0F156bC4uLSP1XHDOySnChg==
   dependencies:
     "@types/body-parser" "*"
-    "@types/express-serve-static-core" "*"
+    "@types/express-serve-static-core" "^4.17.18"
     "@types/qs" "*"
     "@types/serve-static" "*"
 
@@ -1067,6 +1110,11 @@
   resolved "https://registry.yarnpkg.com/@types/http-assert/-/http-assert-1.5.1.tgz#d775e93630c2469c2f980fc27e3143240335db3b"
   integrity sha512-PGAK759pxyfXE78NbKxyfRcWYA/KwW17X290cNev/qAsn9eQIxkH4shoNBafH37wewhDG/0p1cHPbK6+SzZjWQ==
 
+"@types/http-errors@*":
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-1.8.0.tgz#682477dbbbd07cd032731cb3b0e7eaee3d026b69"
+  integrity sha512-2aoSC4UUbHDj2uCsCxcG/vRMXey/m17bC7UwitVm5hn22nI8O8Y9iDpA76Orc+DWkQ4zZrOKEshCqR/jSuXAHA==
+
 "@types/keygrip@*":
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/@types/keygrip/-/keygrip-1.0.2.tgz#513abfd256d7ad0bf1ee1873606317b33b1b2a72"
@@ -1111,54 +1159,60 @@
     "@types/koa-send" "*"
 
 "@types/koa@*", "@types/koa@^2.0.48":
-  version "2.11.3"
-  resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.11.3.tgz#540ece376581b12beadf9a417dd1731bc31c16ce"
-  integrity sha512-ABxVkrNWa4O/Jp24EYI/hRNqEVRlhB9g09p48neQp4m3xL1TJtdWk2NyNQSMCU45ejeELMQZBYyfstyVvO2H3Q==
+  version "2.13.1"
+  resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.13.1.tgz#e29877a6b5ad3744ab1024f6ec75b8cbf6ec45db"
+  integrity sha512-Qbno7FWom9nNqu0yHZ6A0+RWt4mrYBhw3wpBAQ3+IuzGcLlfeYkzZrnMq5wsxulN2np8M4KKeUpTodsOsSad5Q==
   dependencies:
     "@types/accepts" "*"
     "@types/content-disposition" "*"
     "@types/cookies" "*"
     "@types/http-assert" "*"
+    "@types/http-errors" "*"
     "@types/keygrip" "*"
     "@types/koa-compose" "*"
     "@types/node" "*"
 
 "@types/koa__cors@^3.0.1":
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/@types/koa__cors/-/koa__cors-3.0.1.tgz#a8cf8535f0fe682c9421f1b9379837c585f8b66b"
-  integrity sha512-loqZNXliley8kncc4wrX9KMqLGN6YfiaO3a3VFX+yVkkXJwOrZU4lipdudNjw5mFyC+5hd7h9075hQWcVVpeOg==
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/@types/koa__cors/-/koa__cors-3.0.2.tgz#578917ffca964e98f5e9849996ae1eeda7c15704"
+  integrity sha512-gBetQR0DJ9JTG1YQoW33BADHCrDPJGiJUKUUcEPJwW1A2unzpIMhorEpXB6eMaaXTaqHLemcGnq3RmH9XaryRQ==
   dependencies:
     "@types/koa" "*"
 
-"@types/lodash@^4.14.162":
-  version "4.14.162"
-  resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.162.tgz#65d78c397e0d883f44afbf1f7ba9867022411470"
-  integrity sha512-alvcho1kRUnnD1Gcl4J+hK0eencvzq9rmzvFPRmP5rPHx9VVsJj6bKLTATPVf9ktgv4ujzh7T+XWKp+jhuODig==
+"@types/lodash@^4.14.168":
+  version "4.14.168"
+  resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.168.tgz#fe24632e79b7ade3f132891afff86caa5e5ce008"
+  integrity sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q==
 
 "@types/lru-cache@^5.1.0":
   version "5.1.0"
   resolved "https://registry.yarnpkg.com/@types/lru-cache/-/lru-cache-5.1.0.tgz#57f228f2b80c046b4a1bd5cac031f81f207f4f03"
   integrity sha512-RaE0B+14ToE4l6UqdarKPnXwVDuigfFv+5j9Dze/Nqr23yyuqdNvzcZi3xB+3Agvi5R4EOgAksfv3lXX4vBt9w==
 
-"@types/mime@*":
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.2.tgz#857a118d8634c84bba7ae14088e4508490cd5da5"
-  integrity sha512-4kPlzbljFcsttWEq6aBW0OZe6BDajAmyvr2xknBG92tejQnvdGtT9+kXSZ580DqpxY9qG2xeQVF9Dq0ymUTo5Q==
+"@types/mime-types@^2.1.0":
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/@types/mime-types/-/mime-types-2.1.0.tgz#9ca52cda363f699c69466c2a6ccdaad913ea7a73"
+  integrity sha1-nKUs2jY/aZxpRmwqbM2q2RPqenM=
+
+"@types/mime@^1":
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a"
+  integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==
 
 "@types/minimatch@^3.0.3":
-  version "3.0.3"
-  resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
-  integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.4.tgz#f0ec25dbf2f0e4b18647313ac031134ca5b24b21"
+  integrity sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==
 
-"@types/mocha@^8.0.3":
-  version "8.0.3"
-  resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.0.3.tgz#51b21b6acb6d1b923bbdc7725c38f9f455166402"
-  integrity sha512-vyxR57nv8NfcU0GZu8EUXZLTbCMupIUwy95LJ6lllN+JRPG25CwMHoB1q5xKh8YKhQnHYRAn4yW2yuHbf/5xgg==
+"@types/mocha@^8.2.2":
+  version "8.2.2"
+  resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.2.2.tgz#91daa226eb8c2ff261e6a8cbf8c7304641e095e0"
+  integrity sha512-Lwh0lzzqT5Pqh6z61P3c3P5nm6fzQK/MMHl9UKeneAeInVflBSz1O2EkX6gM6xfJd7FBXBY5purtLx7fUiZ7Hw==
 
 "@types/node@*":
-  version "14.0.14"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.14.tgz#24a0b5959f16ac141aeb0c5b3cd7a15b7c64cbce"
-  integrity sha512-syUgf67ZQpaJj01/tRTknkMNoBBLWJOBODF0Zm4NrXmiSuxjymFrxnTu1QVYRubhVkRcZLYZG8STTwJRdVm/WQ==
+  version "14.14.37"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.37.tgz#a3dd8da4eb84a996c36e331df98d82abd76b516e"
+  integrity sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw==
 
 "@types/path-is-inside@^1.0.0":
   version "1.0.0"
@@ -1166,9 +1220,9 @@
   integrity sha512-hfnXRGugz+McgX2jxyy5qz9sB21LRzlGn24zlwN2KEgoPtEvjzNRrLtUkOOebPDPZl3Rq7ywKxYvylVcEZDnEw==
 
 "@types/qs@*":
-  version "6.9.3"
-  resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.3.tgz#b755a0934564a200d3efdf88546ec93c369abd03"
-  integrity sha512-7s9EQWupR1fTc2pSMtXRQ9w9gLOcrJn+h7HOXw4evxyvVqMi4f+q7d2tnFe3ng3SNHjtK+0EzGMGFUQX4/AQRA==
+  version "6.9.6"
+  resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.6.tgz#df9c3c8b31a247ec315e6996566be3171df4b3b1"
+  integrity sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA==
 
 "@types/range-parser@*":
   version "1.2.3"
@@ -1183,24 +1237,19 @@
     "@types/node" "*"
 
 "@types/serve-static@*":
-  version "1.13.4"
-  resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.4.tgz#6662a93583e5a6cabca1b23592eb91e12fa80e7c"
-  integrity sha512-jTDt0o/YbpNwZbQmE/+2e+lfjJEJJR0I3OFaKQKPWkASkCoW3i6fsUnqudSMcNAfbtmADGu8f4MV4q+GqULmug==
+  version "1.13.9"
+  resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.9.tgz#aacf28a85a05ee29a11fb7c3ead935ac56f33e4e"
+  integrity sha512-ZFqF6qa48XsPdjXV5Gsz0Zqmux2PerNd3a/ktL45mHpa19cuMi/cL8tcxdAx497yRh+QtYPuofjT9oWw9P7nkA==
   dependencies:
-    "@types/express-serve-static-core" "*"
-    "@types/mime" "*"
+    "@types/mime" "^1"
+    "@types/node" "*"
 
-"@types/sinon@^9.0.8":
-  version "9.0.8"
-  resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-9.0.8.tgz#1ed0038d356784f75b086104ef83bfd4130bb81b"
-  integrity sha512-IVnI820FZFMGI+u1R+2VdRaD/82YIQTdqLYC9DLPszZuynAJDtCvCtCs3bmyL66s7FqRM3+LPX7DhHnVTaagDw==
+"@types/sinon@^10.0.0":
+  version "10.0.0"
+  resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-10.0.0.tgz#eecc3847af03d45ffe53d55aaaaf6ecb28b5e584"
+  integrity sha512-jDZ55oCKxqlDmoTBBbBBEx+N8ZraUVhggMZ9T5t+6/Dh8/4NiOjSUfpLrPiEwxQDlAe3wpAkoXhWvE6LibtsMQ==
   dependencies:
-    "@types/sinonjs__fake-timers" "*"
-
-"@types/sinonjs__fake-timers@*":
-  version "6.0.2"
-  resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.2.tgz#3a84cf5ec3249439015e14049bd3161419bf9eae"
-  integrity sha512-dIPoZ3g5gcx9zZEszaxLSVTvMReD3xxyyDnQUjA6IYDG9Ba2AV0otMPs+77sG9ojB4Qr2N2Vk5RnKeuA0X/0bg==
+    "@sinonjs/fake-timers" "^7.0.4"
 
 "@types/whatwg-url@^6.4.0":
   version "6.4.0"
@@ -1209,25 +1258,25 @@
   dependencies:
     "@types/node" "*"
 
-"@webcomponents/shadycss@^1.9.1":
-  version "1.9.4"
-  resolved "https://registry.yarnpkg.com/@webcomponents/shadycss/-/shadycss-1.9.4.tgz#4f9d8ea1526bab084c60b53d4854dc39fdb2bb48"
-  integrity sha512-tgNcVEaKssyeZPbUBjVQf4aryO5Fi7fxRvOxV982ZJuRVDcefmIblBh0SXAbcvAAlQ2zpNEP4SuQUnr8uApIpw==
+"@ungap/promise-all-settled@1.1.2":
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44"
+  integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==
 
-"@webcomponents/shadycss@^1.9.4":
-  version "1.10.0"
-  resolved "https://registry.yarnpkg.com/@webcomponents/shadycss/-/shadycss-1.10.0.tgz#7a80ec1e8b271fb3f0cc02cd4358b877a303545d"
-  integrity sha512-UMS+dF4DXDrcUmQqK6aLd/3mFyfGktKG/hZR6FtrsQK/INO07G0H8FxElLkuvHj0iePeZGpR7R4lWFTvX7rc9g==
+"@webcomponents/shadycss@^1.10.2", "@webcomponents/shadycss@^1.9.1":
+  version "1.10.2"
+  resolved "https://registry.yarnpkg.com/@webcomponents/shadycss/-/shadycss-1.10.2.tgz#40e03cab6dc5e12f199949ba2b79e02f183d1e7b"
+  integrity sha512-9Iseu8bRtecb0klvv+WXZOVZatsRkbaH7M97Z+f+Pt909R4lDfgUODAnra23DOZTpeMTAkVpf4m/FZztN7Ox1A==
 
-"@webcomponents/webcomponentsjs@^2.4.0":
-  version "2.4.3"
-  resolved "https://registry.yarnpkg.com/@webcomponents/webcomponentsjs/-/webcomponentsjs-2.4.3.tgz#384f4f6d54563ba465fb4df21fe89e78a76fc530"
-  integrity sha512-cV4+sAmshf8ysU2USutrSRYQkJzEYKHsRCGa0CkMElGpG5747VHtkfsW3NdVIBV/m2MDKXTDydT4lkrysH7IFA==
+"@webcomponents/webcomponentsjs@^2.4.0", "@webcomponents/webcomponentsjs@^2.5.0":
+  version "2.5.0"
+  resolved "https://registry.yarnpkg.com/@webcomponents/webcomponentsjs/-/webcomponentsjs-2.5.0.tgz#61b27785a6ad5bfd68fa018201fe418b118cb38d"
+  integrity sha512-C0l51MWQZ9kLzcxOZtniOMohpIFdCLZum7/TEHv3XWFc1Fvt5HCpbSX84x8ltka/JuNKcuiDnxXFkiB2gaePcg==
 
 abortcontroller-polyfill@^1.4.0:
-  version "1.4.0"
-  resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.4.0.tgz#0d5eb58e522a461774af8086414f68e1dda7a6c4"
-  integrity sha512-3ZFfCRfDzx3GFjO6RAkYx81lPGpUS20ISxux9gLxuKnqafNcFQo59+IoZqpO2WvQlyc287B62HDnDdNYRmlvWA==
+  version "1.7.1"
+  resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.1.tgz#27084bac87d78a7224c8ee78135d05df430c2d2f"
+  integrity sha512-yml9NiDEH4M4p0G4AcPkg8AAa4mF3nfYF28VQxaokpO67j9H7gWgmsVWJ/f1Rn+PzsnDYvzJzWIQzCqDKRvWlA==
 
 accepts@^1.3.5, accepts@~1.3.4:
   version "1.3.7"
@@ -1247,20 +1296,20 @@
   resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
   integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=
 
-ajv@^6.5.5:
-  version "6.12.2"
-  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd"
-  integrity sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==
+ajv@^6.12.3:
+  version "6.12.6"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
+  integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
   dependencies:
     fast-deep-equal "^3.1.1"
     fast-json-stable-stringify "^2.0.0"
     json-schema-traverse "^0.4.1"
     uri-js "^4.2.2"
 
-ansi-colors@3.2.3:
-  version "3.2.3"
-  resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813"
-  integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==
+ansi-colors@4.1.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
+  integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
 
 ansi-regex@^3.0.0:
   version "3.0.0"
@@ -1272,39 +1321,49 @@
   resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
   integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
 
-ansi-styles@^3.2.0, ansi-styles@^3.2.1:
+ansi-regex@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
+  integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==
+
+ansi-styles@^3.2.1:
   version "3.2.1"
   resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
   integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
   dependencies:
     color-convert "^1.9.0"
 
+ansi-styles@^4.0.0, ansi-styles@^4.1.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
+  integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
+  dependencies:
+    color-convert "^2.0.1"
+
 any-promise@^1.0.0, any-promise@^1.1.0:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
   integrity sha1-q8av7tzqUugJzcA3au0845Y10X8=
 
 anymatch@~3.1.1:
-  version "3.1.1"
-  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142"
-  integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
+  integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
   dependencies:
     normalize-path "^3.0.0"
     picomatch "^2.0.4"
 
-argparse@^1.0.7:
-  version "1.0.10"
-  resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
-  integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
-  dependencies:
-    sprintf-js "~1.0.2"
+argparse@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
+  integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
 
 array-back@^3.0.1:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0"
   integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==
 
-array-back@^4.0.0, array-back@^4.0.1:
+array-back@^4.0.1:
   version "4.0.1"
   resolved "https://registry.yarnpkg.com/array-back/-/array-back-4.0.1.tgz#9b80312935a52062e1a233a9c7abeb5481b30e90"
   integrity sha512-Z/JnaVEXv+A9xabHzN43FiiiWEE7gPCRXMrVmRm00tWbjZRul1iHm7ECzlyNq1p4a4ATXz+G9FJ3GqGOkOV3fg==
@@ -1359,9 +1418,9 @@
   integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
 
 aws4@^1.8.0:
-  version "1.10.0"
-  resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.0.tgz#a17b3a8ea811060e74d47d306122400ad4497ae2"
-  integrity sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==
+  version "1.11.0"
+  resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
+  integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
 
 babel-plugin-dynamic-import-node@^2.3.3:
   version "2.3.3"
@@ -1380,15 +1439,39 @@
     istanbul-lib-instrument "^3.3.0"
     test-exclude "^5.2.3"
 
+babel-plugin-polyfill-corejs2@^0.1.4:
+  version "0.1.10"
+  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.1.10.tgz#a2c5c245f56c0cac3dbddbf0726a46b24f0f81d1"
+  integrity sha512-DO95wD4g0A8KRaHKi0D51NdGXzvpqVLnLu5BTvDlpqUEpTmeEtypgC1xqesORaWmiUOQI14UHKlzNd9iZ2G3ZA==
+  dependencies:
+    "@babel/compat-data" "^7.13.0"
+    "@babel/helper-define-polyfill-provider" "^0.1.5"
+    semver "^6.1.1"
+
+babel-plugin-polyfill-corejs3@^0.1.3:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.1.7.tgz#80449d9d6f2274912e05d9e182b54816904befd0"
+  integrity sha512-u+gbS9bbPhZWEeyy1oR/YaaSpod/KDT07arZHb80aTpl8H5ZBq+uN1nN9/xtX7jQyfLdPfoqI4Rue/MQSWJquw==
+  dependencies:
+    "@babel/helper-define-polyfill-provider" "^0.1.5"
+    core-js-compat "^3.8.1"
+
+babel-plugin-polyfill-regenerator@^0.1.2:
+  version "0.1.6"
+  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.1.6.tgz#0fe06a026fe0faa628ccc8ba3302da0a6ce02f3f"
+  integrity sha512-OUrYG9iKPKz8NxswXbRAdSwF0GhRdIEMTloQATJi4bDuFqrXaXcCUT/VGNrr8pBcjMh1RxZ7Xt9cytVJTJfvMg==
+  dependencies:
+    "@babel/helper-define-polyfill-provider" "^0.1.5"
+
 backo2@1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
   integrity sha1-MasayLEpNjRj41s+u2n038+6eUc=
 
 balanced-match@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
-  integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
+  integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
 
 base64-arraybuffer@0.1.5:
   version "0.1.5"
@@ -1415,9 +1498,9 @@
     callsite "1.0.0"
 
 binary-extensions@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c"
-  integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
+  integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
 
 blob@0.0.5:
   version "0.0.5"
@@ -1474,15 +1557,16 @@
     semver "^7.3.2"
     useragent "^2.3.0"
 
-browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.8.5, browserslist@^4.9.1:
-  version "4.12.2"
-  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.12.2.tgz#76653d7e4c57caa8a1a28513e2f4e197dc11a711"
-  integrity sha512-MfZaeYqR8StRZdstAK9hCKDd2StvePCYp5rHzQCPicUjfFliDgmuaBNPHYUTpAywBN8+Wc/d7NYVFkO0aqaBUw==
+browserslist@*, browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.16.0, browserslist@^4.16.3, browserslist@^4.9.1:
+  version "4.16.3"
+  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.3.tgz#340aa46940d7db878748567c5dea24a48ddf3717"
+  integrity sha512-vIyhWmIkULaq04Gt93txdh+j02yX/JzlyhLYbV3YQCn/zvES3JnY7TifHHvvr1w5hTDluNKMkV05cs4vy8Q7sw==
   dependencies:
-    caniuse-lite "^1.0.30001088"
-    electron-to-chromium "^1.3.483"
-    escalade "^3.0.1"
-    node-releases "^1.1.58"
+    caniuse-lite "^1.0.30001181"
+    colorette "^1.2.1"
+    electron-to-chromium "^1.3.649"
+    escalade "^3.1.1"
+    node-releases "^1.1.70"
 
 buffer-alloc-unsafe@^1.1.0:
   version "1.1.0"
@@ -1508,9 +1592,9 @@
   integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
 
 builtin-modules@^3.1.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.1.0.tgz#aad97c15131eb76b65b50ef208e7584cd76a7484"
-  integrity sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.2.0.tgz#45d5db99e7ee5e6bc4f362e008bf917ab5049887"
+  integrity sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==
 
 bytes@3.1.0, bytes@^3.0.0:
   version "3.1.0"
@@ -1525,24 +1609,37 @@
     mime-types "^2.1.18"
     ylru "^1.2.0"
 
+call-bind@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
+  integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==
+  dependencies:
+    function-bind "^1.1.1"
+    get-intrinsic "^1.0.2"
+
 callsite@1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20"
   integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA=
 
-camel-case@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73"
-  integrity sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=
+camel-case@^4.1.1:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a"
+  integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==
   dependencies:
-    no-case "^2.2.0"
-    upper-case "^1.1.1"
+    pascal-case "^3.1.2"
+    tslib "^2.0.3"
 
-camelcase@^5.0.0, camelcase@^5.3.1:
+camelcase@^5.3.1:
   version "5.3.1"
   resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
   integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
 
+camelcase@^6.0.0:
+  version "6.2.0"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809"
+  integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==
+
 caniuse-api@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0"
@@ -1553,26 +1650,26 @@
     lodash.memoize "^4.1.2"
     lodash.uniq "^4.5.0"
 
-caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001033, caniuse-lite@^1.0.30001088:
-  version "1.0.30001093"
-  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001093.tgz#833e80f64b1a0455cbceed2a4a3baf19e4abd312"
-  integrity sha512-0+ODNoOjtWD5eS9aaIpf4K0gQqZfILNY4WSNuYzeT1sXni+lMrrVjc0odEobJt6wrODofDZUX8XYi/5y7+xl8g==
+caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001033, caniuse-lite@^1.0.30001181:
+  version "1.0.30001207"
+  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001207.tgz#364d47d35a3007e528f69adb6fecb07c2bb2cc50"
+  integrity sha512-UPQZdmAsyp2qfCTiMU/zqGSWOYaY9F9LL61V8f+8MrubsaDGpaHD9HRV/EWZGULZn0Hxu48SKzI5DgFwTvHuYw==
 
 caseless@~0.12.0:
   version "0.12.0"
   resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
   integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
 
-chai@^4.2.0:
-  version "4.2.0"
-  resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5"
-  integrity sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==
+chai@^4.3.4:
+  version "4.3.4"
+  resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.4.tgz#b55e655b31e1eac7099be4c08c21964fce2e6c49"
+  integrity sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==
   dependencies:
     assertion-error "^1.1.0"
     check-error "^1.0.2"
     deep-eql "^3.0.1"
     get-func-name "^2.0.0"
-    pathval "^1.1.0"
+    pathval "^1.1.1"
     type-detect "^4.0.5"
 
 chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.2:
@@ -1584,15 +1681,23 @@
     escape-string-regexp "^1.0.5"
     supports-color "^5.3.0"
 
+chalk@^4.0.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a"
+  integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==
+  dependencies:
+    ansi-styles "^4.1.0"
+    supports-color "^7.1.0"
+
 check-error@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
   integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=
 
-chokidar@3.3.0:
-  version "3.3.0"
-  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.0.tgz#12c0714668c55800f659e262d4962a97faf554a6"
-  integrity sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==
+chokidar@3.5.1, chokidar@^3.0.0, chokidar@^3.4.3:
+  version "3.5.1"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a"
+  integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==
   dependencies:
     anymatch "~3.1.1"
     braces "~3.0.2"
@@ -1600,40 +1705,25 @@
     is-binary-path "~2.1.0"
     is-glob "~4.0.1"
     normalize-path "~3.0.0"
-    readdirp "~3.2.0"
+    readdirp "~3.5.0"
   optionalDependencies:
-    fsevents "~2.1.1"
+    fsevents "~2.3.1"
 
-chokidar@^3.0.0:
-  version "3.3.1"
-  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.1.tgz#c84e5b3d18d9a4d77558fef466b1bf16bbeb3450"
-  integrity sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==
-  dependencies:
-    anymatch "~3.1.1"
-    braces "~3.0.2"
-    glob-parent "~5.1.0"
-    is-binary-path "~2.1.0"
-    is-glob "~4.0.1"
-    normalize-path "~3.0.0"
-    readdirp "~3.3.0"
-  optionalDependencies:
-    fsevents "~2.1.2"
-
-clean-css@^4.2.1:
+clean-css@^4.2.3:
   version "4.2.3"
   resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.3.tgz#507b5de7d97b48ee53d84adb0160ff6216380f78"
   integrity sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==
   dependencies:
     source-map "~0.6.0"
 
-cliui@^5.0.0:
-  version "5.0.0"
-  resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5"
-  integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==
+cliui@^7.0.2:
+  version "7.0.4"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
+  integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==
   dependencies:
-    string-width "^3.1.0"
-    strip-ansi "^5.2.0"
-    wrap-ansi "^5.1.0"
+    string-width "^4.2.0"
+    strip-ansi "^6.0.0"
+    wrap-ansi "^7.0.0"
 
 clone@^2.1.2:
   version "2.1.2"
@@ -1652,11 +1742,28 @@
   dependencies:
     color-name "1.1.3"
 
+color-convert@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
+  integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
+  dependencies:
+    color-name "~1.1.4"
+
 color-name@1.1.3:
   version "1.1.3"
   resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
   integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
 
+color-name@~1.1.4:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+  integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+
+colorette@^1.2.1:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
+  integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==
+
 colors@^1.1.0:
   version "1.4.0"
   resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
@@ -1680,20 +1787,25 @@
     typical "^4.0.0"
 
 command-line-usage@^6.1.0:
-  version "6.1.0"
-  resolved "https://registry.yarnpkg.com/command-line-usage/-/command-line-usage-6.1.0.tgz#f28376a3da3361ff3d36cfd31c3c22c9a64c7cb6"
-  integrity sha512-Ew1clU4pkUeo6AFVDFxCbnN7GIZfXl48HIOQeFQnkO3oOqvpI7wdqtLRwv9iOCZ/7A+z4csVZeiDdEcj8g6Wiw==
+  version "6.1.1"
+  resolved "https://registry.yarnpkg.com/command-line-usage/-/command-line-usage-6.1.1.tgz#c908e28686108917758a49f45efb4f02f76bc03f"
+  integrity sha512-F59pEuAR9o1SF/bD0dQBDluhpT4jJQNWUHEuVBqpDmCUo6gPjCi+m9fCWnWZVR/oG6cMTUms4h+3NPl74wGXvA==
   dependencies:
-    array-back "^4.0.0"
+    array-back "^4.0.1"
     chalk "^2.4.2"
-    table-layout "^1.0.0"
+    table-layout "^1.0.1"
     typical "^5.2.0"
 
-commander@^2.19.0, commander@^2.20.0:
+commander@^2.20.0:
   version "2.20.3"
   resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
   integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
 
+commander@^4.1.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
+  integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
+
 component-bind@1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1"
@@ -1763,17 +1875,17 @@
     depd "~2.0.0"
     keygrip "~1.1.0"
 
-core-js-bundle@^3.6.0:
-  version "3.6.5"
-  resolved "https://registry.yarnpkg.com/core-js-bundle/-/core-js-bundle-3.6.5.tgz#3a425ad66ad19aeefea89acfd48cff674ff58590"
-  integrity sha512-awf49McIBT3sDXceSex69w/i7PMXQwxI4ZqknCtaYbW4Q0u0HUZiaQLlPD6pU2nFBofIowgWIS1ANgHjqnQu4Q==
+core-js-bundle@^3.6.0, core-js-bundle@^3.8.1:
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/core-js-bundle/-/core-js-bundle-3.10.0.tgz#8559ce25d36f8094bcafdf7d1a24d50c706dcbe5"
+  integrity sha512-Rh+60FxNOd23Fm35vK/P3U1usjte2VNKBBW9bGZym5cV2Cc9pgviMQjSEOe8llIZAZjbr5NuL4GoeBK8DM3ewg==
 
-core-js-compat@^3.6.2:
-  version "3.6.5"
-  resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.5.tgz#2a51d9a4e25dfd6e690251aa81f99e3c05481f1c"
-  integrity sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng==
+core-js-compat@^3.8.1, core-js-compat@^3.9.0:
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.10.0.tgz#3600dc72869673c110215ee7a005a8609dea0fe1"
+  integrity sha512-9yVewub2MXNYyGvuLnMHcN1k9RkvB7/ofktpeKTIaASyB88YYqGzUnu0ywMMhJrDHOMiTjSHWGzR+i7Wb9Z1kQ==
   dependencies:
-    browserslist "^4.8.5"
+    browserslist "^4.16.3"
     semver "7.0.0"
 
 core-util-is@1.0.2:
@@ -1799,9 +1911,9 @@
   integrity sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==
 
 debounce@^1.2.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.0.tgz#44a540abc0ea9943018dc0eaa95cce87f65cd131"
-  integrity sha512-mYtLl1xfZLi1m4RtQYlZgJUNQjl4ZxVnHzIR8nLLgi4q1YT8o/WM+MK/f8yfcc9s5Ir5zRaPZyZU6xs1Syoocg==
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5"
+  integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==
 
 debug@2.6.9:
   version "2.6.9"
@@ -1810,17 +1922,17 @@
   dependencies:
     ms "2.0.0"
 
-debug@3.2.6, debug@^3.0.0, debug@^3.1.0, debug@^3.1.1, debug@^3.2.6:
-  version "3.2.6"
-  resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
-  integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
+debug@4.3.1, debug@^4.1.0, debug@^4.1.1:
+  version "4.3.1"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
+  integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
   dependencies:
-    ms "^2.1.1"
+    ms "2.1.2"
 
-debug@^4.1.0, debug@^4.1.1:
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
-  integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
+debug@^3.1.0, debug@^3.1.1, debug@^3.2.6:
+  version "3.2.7"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
+  integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
   dependencies:
     ms "^2.1.1"
 
@@ -1831,10 +1943,10 @@
   dependencies:
     ms "2.0.0"
 
-decamelize@^1.2.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
-  integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
+decamelize@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837"
+  integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==
 
 deep-eql@^3.0.1:
   version "3.0.1"
@@ -1858,7 +1970,7 @@
   resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
   integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
 
-define-properties@^1.1.2, define-properties@^1.1.3:
+define-properties@^1.1.3:
   version "1.1.3"
   resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
   integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
@@ -1875,16 +1987,16 @@
   resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
   integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
 
-depd@^1.1.2, depd@~1.1.2:
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
-  integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
-
-depd@~2.0.0:
+depd@^2.0.0, depd@~2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
   integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
 
+depd@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
+  integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
+
 destroy@^1.0.4:
   version "1.0.4"
   resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
@@ -1895,10 +2007,10 @@
   resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c"
   integrity sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=
 
-diff@3.5.0:
-  version "3.5.0"
-  resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
-  integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
+diff@5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b"
+  integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==
 
 diff@^4.0.2:
   version "4.0.2"
@@ -1915,6 +2027,14 @@
     extend "^3.0.0"
     void-elements "^2.0.0"
 
+dot-case@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751"
+  integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==
+  dependencies:
+    no-case "^3.0.4"
+    tslib "^2.0.3"
+
 dynamic-import-polyfill@^0.1.1:
   version "0.1.1"
   resolved "https://registry.yarnpkg.com/dynamic-import-polyfill/-/dynamic-import-polyfill-0.1.1.tgz#e1f9eb1876ee242bd56572f8ed4df768e143083f"
@@ -1933,15 +2053,15 @@
   resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
   integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
 
-electron-to-chromium@^1.3.483:
-  version "1.3.486"
-  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.486.tgz#90856e6c9f488079225cf5a0b4d4af6c241e0965"
-  integrity sha512-fmnACh6Jiuagm9tAfEZNe6QrwvOYAC5y0BwzoEOGCsbqriKOCaafXf3lsIvL55xa75Jmg4oboI7f5tMuoXrjNg==
+electron-to-chromium@^1.3.649:
+  version "1.3.709"
+  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.709.tgz#d7be0b5686a2fdfe8bad898faa3a428d04d8f656"
+  integrity sha512-LolItk2/ikSGQ7SN8UkuKVNMBZp3RG7Itgaxj1npsHRzQobj9JjMneZOZfLhtwlYBe5fCJ75k+cVCiDFUs23oA==
 
-emoji-regex@^7.0.1:
-  version "7.0.3"
-  resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
-  integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
+emoji-regex@^8.0.0:
+  version "8.0.0"
+  resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
+  integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
 
 encodeurl@^1.0.2, encodeurl@~1.0.2:
   version "1.0.2"
@@ -2007,41 +2127,24 @@
   dependencies:
     is-arrayish "^0.2.1"
 
-es-abstract@^1.17.0-next.1, es-abstract@^1.17.5:
-  version "1.17.6"
-  resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.6.tgz#9142071707857b2cacc7b89ecb670316c3e2d52a"
-  integrity sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==
+es-dev-server@^1.57.0:
+  version "1.60.2"
+  resolved "https://registry.yarnpkg.com/es-dev-server/-/es-dev-server-1.60.2.tgz#cca56fe452d46c3ec531c19745e0aa9d7b71e1b3"
+  integrity sha512-Lp9kZzawJ35HDKiqLNb/YbD2VufF+3tdxHgbP/kfdLI5JLgDJV4SuKTWWny3ZuBUAlZKGre7a0iXUByGQqfdPA==
   dependencies:
-    es-to-primitive "^1.2.1"
-    function-bind "^1.1.1"
-    has "^1.0.3"
-    has-symbols "^1.0.1"
-    is-callable "^1.2.0"
-    is-regex "^1.1.0"
-    object-inspect "^1.7.0"
-    object-keys "^1.1.1"
-    object.assign "^4.1.0"
-    string.prototype.trimend "^1.0.1"
-    string.prototype.trimstart "^1.0.1"
-
-es-dev-server@^1.56.0:
-  version "1.56.0"
-  resolved "https://registry.yarnpkg.com/es-dev-server/-/es-dev-server-1.56.0.tgz#8703af87595f02fe9a1c92a07e64b7c7cc915a87"
-  integrity sha512-SL4CXdiku0hiB8zpsBLtEd7b8etIZE6IV0tIi02m0CcpTYV0rDMEvCBUYsQIN5hggJDDTBURgQjOWcT5kQv2eA==
-  dependencies:
-    "@babel/core" "^7.9.0"
-    "@babel/plugin-proposal-dynamic-import" "^7.8.3"
-    "@babel/plugin-proposal-nullish-coalescing-operator" "^7.8.3"
-    "@babel/plugin-proposal-optional-chaining" "^7.9.0"
+    "@babel/core" "^7.11.1"
+    "@babel/plugin-proposal-dynamic-import" "^7.10.4"
+    "@babel/plugin-proposal-nullish-coalescing-operator" "^7.10.4"
+    "@babel/plugin-proposal-optional-chaining" "^7.11.0"
     "@babel/plugin-syntax-class-properties" "^7.8.3"
-    "@babel/plugin-syntax-import-meta" "^7.8.3"
+    "@babel/plugin-syntax-import-meta" "^7.10.4"
     "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
     "@babel/plugin-syntax-numeric-separator" "^7.8.3"
     "@babel/plugin-syntax-optional-chaining" "^7.8.3"
     "@babel/plugin-transform-template-literals" "^7.8.3"
     "@babel/preset-env" "^7.9.0"
     "@koa/cors" "^3.1.0"
-    "@open-wc/building-utils" "^2.18.0"
+    "@open-wc/building-utils" "^2.18.3"
     "@rollup/plugin-node-resolve" "^7.1.1"
     "@rollup/pluginutils" "^3.0.0"
     "@types/babel__core" "^7.1.3"
@@ -2057,6 +2160,7 @@
     "@types/koa-static" "^4.0.1"
     "@types/koa__cors" "^3.0.1"
     "@types/lru-cache" "^5.1.0"
+    "@types/mime-types" "^2.1.0"
     "@types/minimatch" "^3.0.3"
     "@types/path-is-inside" "^1.0.0"
     "@types/whatwg-url" "^6.4.0"
@@ -2085,7 +2189,7 @@
     open "^7.0.3"
     parse5 "^5.1.1"
     path-is-inside "^1.0.2"
-    polyfills-loader "^1.6.1"
+    polyfills-loader "^1.7.4"
     portfinder "^1.0.21"
     rollup "^2.7.2"
     strip-ansi "^5.2.0"
@@ -2095,44 +2199,35 @@
     whatwg-url "^7.0.0"
 
 es-module-lexer@^0.3.13:
-  version "0.3.24"
-  resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.3.24.tgz#e6b2900758e9e210d23aec2092efc13ca235adea"
-  integrity sha512-jm/i7KdJtaMDle921xIsA/MQQOGuZ6goYxhlV+k+gQNI7FtP4N6jknrmJvj++3ODpiyFGwQ4PIstJfHJQJNc+g==
+  version "0.3.26"
+  resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.3.26.tgz#7b507044e97d5b03b01d4392c74ffeb9c177a83b"
+  integrity sha512-Va0Q/xqtrss45hWzP8CZJwzGSZJjDM5/MJRE3IXXnUCcVLElR9BRaE9F62BopysASyc4nM3uwhSW7FFB9nlWAA==
 
-es-module-shims@^0.4.6:
+es-module-shims@^0.4.6, es-module-shims@^0.4.7:
   version "0.4.7"
   resolved "https://registry.yarnpkg.com/es-module-shims/-/es-module-shims-0.4.7.tgz#1419b65bbd38dfe91ab8ea5d7b4b454561e44641"
   integrity sha512-0LTiSQoPWwdcaTVIQXhGlaDwTneD0g9/tnH1PNs3zHFFH+xoCeJclDM3rQeqF9nurXPfMKm3l9+kfPRa5VpbKg==
 
-es-to-primitive@^1.2.1:
-  version "1.2.1"
-  resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
-  integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
-  dependencies:
-    is-callable "^1.1.4"
-    is-date-object "^1.0.1"
-    is-symbol "^1.0.2"
-
-escalade@^3.0.1:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.0.1.tgz#52568a77443f6927cd0ab9c73129137533c965ed"
-  integrity sha512-DR6NO3h9niOT+MZs7bjxlj2a1k+POu5RN8CLTPX2+i78bRi9eLe7+0zXgUHMnGXWybYcL61E9hGhPKqedy8tQA==
+escalade@^3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
+  integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
 
 escape-html@^1.0.3, escape-html@~1.0.3:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
   integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
 
-escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5:
+escape-string-regexp@4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
+  integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
+
+escape-string-regexp@^1.0.5:
   version "1.0.5"
   resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
   integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
 
-esprima@^4.0.0:
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
-  integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
-
 estree-walker@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700"
@@ -2149,9 +2244,9 @@
   integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
 
 eventemitter3@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb"
-  integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==
+  version "4.0.7"
+  resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
+  integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
 
 extend@^3.0.0, extend@~3.0.2:
   version "3.0.2"
@@ -2205,19 +2300,25 @@
   dependencies:
     array-back "^3.0.1"
 
-find-up@3.0.0, find-up@^3.0.0:
+find-up@5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
+  integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
+  dependencies:
+    locate-path "^6.0.0"
+    path-exists "^4.0.0"
+
+find-up@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
   integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==
   dependencies:
     locate-path "^3.0.0"
 
-flat@^4.1.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2"
-  integrity sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==
-  dependencies:
-    is-buffer "~2.0.3"
+flat@^5.0.2:
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241"
+  integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==
 
 flatted@^2.0.0:
   version "2.0.2"
@@ -2225,11 +2326,9 @@
   integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==
 
 follow-redirects@^1.0.0:
-  version "1.9.0"
-  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.9.0.tgz#8d5bcdc65b7108fe1508649c79c12d732dcedb4f"
-  integrity sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==
-  dependencies:
-    debug "^3.0.0"
+  version "1.13.3"
+  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267"
+  integrity sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==
 
 forever-agent@~0.6.1:
   version "0.6.1"
@@ -2264,27 +2363,22 @@
   resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
   integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
 
-fsevents@~2.1.1:
-  version "2.1.3"
-  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e"
-  integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==
-
-fsevents@~2.1.2:
-  version "2.1.2"
-  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.2.tgz#4c0a1fb34bc68e543b4b82a9ec392bfbda840805"
-  integrity sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==
+fsevents@~2.3.1:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
+  integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
 
 function-bind@^1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
   integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
 
-gensync@^1.0.0-beta.1:
-  version "1.0.0-beta.1"
-  resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269"
-  integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==
+gensync@^1.0.0-beta.2:
+  version "1.0.0-beta.2"
+  resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
+  integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
 
-get-caller-file@^2.0.1:
+get-caller-file@^2.0.5:
   version "2.0.5"
   resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
   integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
@@ -2294,10 +2388,19 @@
   resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"
   integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=
 
+get-intrinsic@^1.0.2:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6"
+  integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==
+  dependencies:
+    function-bind "^1.1.1"
+    has "^1.0.3"
+    has-symbols "^1.0.1"
+
 get-stream@^5.1.0:
-  version "5.1.0"
-  resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9"
-  integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
+  integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
   dependencies:
     pump "^3.0.0"
 
@@ -2309,25 +2412,13 @@
     assert-plus "^1.0.0"
 
 glob-parent@~5.1.0:
-  version "5.1.1"
-  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229"
-  integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
+  integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
   dependencies:
     is-glob "^4.0.1"
 
-glob@7.1.3:
-  version "7.1.3"
-  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
-  integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==
-  dependencies:
-    fs.realpath "^1.0.0"
-    inflight "^1.0.4"
-    inherits "2"
-    minimatch "^3.0.4"
-    once "^1.3.0"
-    path-is-absolute "^1.0.0"
-
-glob@^7.1.1, glob@^7.1.3:
+glob@7.1.6, glob@^7.1.1, glob@^7.1.3:
   version "7.1.6"
   resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
   integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
@@ -2345,9 +2436,9 @@
   integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
 
 graceful-fs@^4.1.2, graceful-fs@^4.1.6:
-  version "4.2.3"
-  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423"
-  integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==
+  version "4.2.6"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee"
+  integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==
 
 growl@1.10.5:
   version "1.10.5"
@@ -2360,11 +2451,11 @@
   integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
 
 har-validator@~5.1.3:
-  version "5.1.3"
-  resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080"
-  integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==
+  version "5.1.5"
+  resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd"
+  integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==
   dependencies:
-    ajv "^6.5.5"
+    ajv "^6.12.3"
     har-schema "^2.0.0"
 
 has-binary2@~1.0.2:
@@ -2389,10 +2480,10 @@
   resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
   integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
 
-has-symbols@^1.0.0, has-symbols@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
-  integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
+has-symbols@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423"
+  integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==
 
 has@^1.0.3:
   version "1.0.3"
@@ -2411,18 +2502,18 @@
   resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488"
   integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==
 
-html-minifier@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-4.0.0.tgz#cca9aad8bce1175e02e17a8c33e46d8988889f56"
-  integrity sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==
+html-minifier-terser@^5.1.1:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz#922e96f1f3bb60832c2634b79884096389b1f054"
+  integrity sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==
   dependencies:
-    camel-case "^3.0.0"
-    clean-css "^4.2.1"
-    commander "^2.19.0"
+    camel-case "^4.1.1"
+    clean-css "^4.2.3"
+    commander "^4.1.1"
     he "^1.2.0"
-    param-case "^2.1.1"
+    param-case "^3.0.3"
     relateurl "^0.2.7"
-    uglify-js "^3.5.1"
+    terser "^4.6.3"
 
 http-assert@^1.3.0:
   version "1.4.1"
@@ -2443,7 +2534,7 @@
     statuses ">= 1.5.0 < 2"
     toidentifier "1.0.0"
 
-http-errors@^1.6.3:
+http-errors@^1.6.3, http-errors@^1.7.3:
   version "1.8.0"
   resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.0.tgz#75d1bbe497e1044f51e4ee9e704a62f28d336507"
   integrity sha512-4I8r0C5JDhT5VkvI47QktDW75rNlGVsUf/8hzjCC/wkWI/jdTRmBb9aI7erSG82r1bjKY3F6k28WnsVxB1C73A==
@@ -2476,9 +2567,9 @@
     toidentifier "1.0.0"
 
 http-proxy@^1.13.0:
-  version "1.18.0"
-  resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.0.tgz#dbe55f63e75a347db7f3d99974f2692a314a6a3a"
-  integrity sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==
+  version "1.18.1"
+  resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549"
+  integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==
   dependencies:
     eventemitter3 "^4.0.0"
     follow-redirects "^1.0.0"
@@ -2528,13 +2619,6 @@
   resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.7.0.tgz#ee16bee978db53516ead2f0a8154b09b400bbdc9"
   integrity sha512-Id0Fij0HsB/vKWGeBe9PxeY45ttRiBmhFyyt/geBdDHBYNctMRTE3dC1U3ujzz3lap+hVXlEcVaB56kZP/eEUg==
 
-invariant@^2.2.2, invariant@^2.2.4:
-  version "2.2.4"
-  resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
-  integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
-  dependencies:
-    loose-envify "^1.0.0"
-
 is-arrayish@^0.2.1:
   version "0.2.1"
   resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
@@ -2547,25 +2631,17 @@
   dependencies:
     binary-extensions "^2.0.0"
 
-is-buffer@~2.0.3:
-  version "2.0.4"
-  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623"
-  integrity sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==
-
-is-callable@^1.1.4, is-callable@^1.2.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb"
-  integrity sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==
-
-is-date-object@^1.0.1:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e"
-  integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==
+is-core-module@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a"
+  integrity sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==
+  dependencies:
+    has "^1.0.3"
 
 is-docker@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.0.0.tgz#2cb0df0e75e2d064fe1864c37cdeacb7b2dcf25b"
-  integrity sha512-pJEdRugimx4fBMra5z2/5iRdZ63OhYV0vr0Dwm5+xtW4D1FvRkB8hamMIhnWfyJeDdyr/aa7BDyNbtG38VxgoQ==
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.0.tgz#b037c8815281edaad6c2562648a5f5f18839d5f7"
+  integrity sha512-K4GwB4i/HzhAzwP/XSlspzRdFTI9N8OxJOyOU7Y5Rz+p+WBokXWVWblaJeBkggthmoSV0OoGTH5thJNvplpkvQ==
 
 is-extglob@^2.1.1:
   version "2.1.1"
@@ -2577,10 +2653,15 @@
   resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
   integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
 
+is-fullwidth-code-point@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
+  integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
+
 is-generator-function@^1.0.7:
-  version "1.0.7"
-  resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.7.tgz#d2132e529bb0000a7f80794d4bdf5cd5e5813522"
-  integrity sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw==
+  version "1.0.8"
+  resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.8.tgz#dfb5c2b120e02b0a8d9d2c6806cd5621aa922f7b"
+  integrity sha512-2Omr/twNtufVZFr1GhxjOMFPAj2sjc/dKaIqBhvo4qciXfJmITGH6ZGd8eZYNHza8t1y0e01AuqRhJwfWp26WQ==
 
 is-glob@^4.0.1, is-glob@~4.0.1:
   version "4.0.1"
@@ -2599,25 +2680,16 @@
   resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
   integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
 
-is-regex@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.0.tgz#ece38e389e490df0dc21caea2bd596f987f767ff"
-  integrity sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==
-  dependencies:
-    has-symbols "^1.0.1"
+is-plain-obj@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287"
+  integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==
 
 is-stream@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3"
   integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==
 
-is-symbol@^1.0.2:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937"
-  integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==
-  dependencies:
-    has-symbols "^1.0.1"
-
 is-typedarray@~1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
@@ -2680,18 +2752,17 @@
     istanbul-lib-coverage "^2.0.5"
     semver "^6.0.0"
 
-"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
+js-tokens@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
   integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
 
-js-yaml@3.13.1:
-  version "3.13.1"
-  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
-  integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
+js-yaml@4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.0.0.tgz#f426bc0ff4b4051926cd588c71113183409a121f"
+  integrity sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==
   dependencies:
-    argparse "^1.0.7"
-    esprima "^4.0.0"
+    argparse "^2.0.1"
 
 jsbn@~0.1.0:
   version "0.1.1"
@@ -2729,9 +2800,9 @@
   integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
 
 json5@^2.1.2:
-  version "2.1.3"
-  resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43"
-  integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3"
+  integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==
   dependencies:
     minimist "^1.2.5"
 
@@ -2753,9 +2824,9 @@
     verror "1.10.0"
 
 just-extend@^4.0.2:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.1.0.tgz#7278a4027d889601640ee0ce0e5a00b992467da4"
-  integrity sha512-ApcjaOdVTJ7y4r08xI5wIqpvwS48Q0PBG4DJROcEkH1f8MdAiNFyFxz3xoL0LWAVwjrwPYZdVHHxhRHcx/uGLA==
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.2.1.tgz#ef5e589afb61e5d66b24eca749409a8939a8c744"
+  integrity sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==
 
 karma-chrome-launcher@^3.1.0:
   version "3.1.0"
@@ -2863,13 +2934,12 @@
   integrity sha1-JzwH7c3Ljfaiwat9We52SRRR7BQ=
 
 koa-send@^5.0.0:
-  version "5.0.0"
-  resolved "https://registry.yarnpkg.com/koa-send/-/koa-send-5.0.0.tgz#5e8441e07ef55737734d7ced25b842e50646e7eb"
-  integrity sha512-90ZotV7t0p3uN9sRwW2D484rAaKIsD8tAVtypw/aBU+ryfV+fR2xrcAwhI8Wl6WRkojLUs/cB9SBSCuIb+IanQ==
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/koa-send/-/koa-send-5.0.1.tgz#39dceebfafb395d0d60beaffba3a70b4f543fe79"
+  integrity sha512-tmcyQ/wXXuxpDxyNXv5yNNkdAMdFRqwtegBXUaowiQzUKqJehttS0x2j0eOZDQAyloAth5w6wwBImnFzkUz3pQ==
   dependencies:
-    debug "^3.1.0"
-    http-errors "^1.6.3"
-    mz "^2.7.0"
+    debug "^4.1.1"
+    http-errors "^1.7.3"
     resolve-path "^1.4.0"
 
 koa-static@^5.0.0:
@@ -2881,9 +2951,9 @@
     koa-send "^5.0.0"
 
 koa@^2.7.0:
-  version "2.13.0"
-  resolved "https://registry.yarnpkg.com/koa/-/koa-2.13.0.tgz#25217e05efd3358a7e5ddec00f0a380c9b71b501"
-  integrity sha512-i/XJVOfPw7npbMv67+bOeXr3gPqOAw6uh5wFyNs3QvJ47tUx3M3V9rIE0//WytY42MKz4l/MXKyGkQ2LQTfLUQ==
+  version "2.13.1"
+  resolved "https://registry.yarnpkg.com/koa/-/koa-2.13.1.tgz#6275172875b27bcfe1d454356a5b6b9f5a9b1051"
+  integrity sha512-Lb2Dloc72auj5vK4X4qqL7B5jyDPQaZucc9sR/71byg7ryoD1NCaCm63CShk9ID9quQvDEi1bGR/iGjCG7As3w==
   dependencies:
     accepts "^1.3.5"
     cache-content-type "^1.0.0"
@@ -2892,7 +2962,7 @@
     cookies "~0.8.0"
     debug "~3.1.0"
     delegates "^1.0.0"
-    depd "^1.1.2"
+    depd "^2.0.0"
     destroy "^1.0.4"
     encodeurl "^1.0.2"
     escape-html "^1.0.3"
@@ -2909,18 +2979,6 @@
     type-is "^1.6.16"
     vary "^1.1.2"
 
-leven@^3.1.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
-  integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==
-
-levenary@^1.1.1:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/levenary/-/levenary-1.1.1.tgz#842a9ee98d2075aa7faeedbe32679e9205f46f77"
-  integrity sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==
-  dependencies:
-    leven "^3.1.0"
-
 load-json-file@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b"
@@ -2939,11 +2997,23 @@
     p-locate "^3.0.0"
     path-exists "^3.0.0"
 
+locate-path@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
+  integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
+  dependencies:
+    p-locate "^5.0.0"
+
 lodash.camelcase@^4.3.0:
   version "4.3.0"
   resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
   integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=
 
+lodash.debounce@^4.0.8:
+  version "4.0.8"
+  resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
+  integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168=
+
 lodash.get@^4.4.2:
   version "4.4.2"
   resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
@@ -2964,17 +3034,17 @@
   resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
   integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
 
-lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15:
-  version "4.17.15"
-  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
-  integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
+lodash@^4.17.14, lodash@^4.17.19, lodash@^4.17.21:
+  version "4.17.21"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
+  integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
 
-log-symbols@3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4"
-  integrity sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==
+log-symbols@4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.0.0.tgz#69b3cc46d20f448eccdb75ea1fa733d9e821c920"
+  integrity sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==
   dependencies:
-    chalk "^2.4.2"
+    chalk "^4.0.0"
 
 log-symbols@^2.1.0:
   version "2.2.0"
@@ -2994,17 +3064,12 @@
     rfdc "^1.1.4"
     streamroller "^1.0.6"
 
-loose-envify@^1.0.0:
-  version "1.4.0"
-  resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
-  integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
+lower-case@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28"
+  integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==
   dependencies:
-    js-tokens "^3.0.0 || ^4.0.0"
-
-lower-case@^1.1.1:
-  version "1.1.4"
-  resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac"
-  integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw=
+    tslib "^2.0.3"
 
 lru-cache@4.1.x:
   version "4.1.5"
@@ -3021,39 +3086,34 @@
   dependencies:
     yallist "^3.0.2"
 
+lru-cache@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
+  integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
+  dependencies:
+    yallist "^4.0.0"
+
 media-typer@0.3.0:
   version "0.3.0"
   resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
   integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
 
-mime-db@1.43.0:
-  version "1.43.0"
-  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58"
-  integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==
+mime-db@1.47.0, "mime-db@>= 1.43.0 < 2":
+  version "1.47.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.47.0.tgz#8cb313e59965d3c05cfbf898915a267af46a335c"
+  integrity sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==
 
-mime-db@1.44.0, "mime-db@>= 1.43.0 < 2":
-  version "1.44.0"
-  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92"
-  integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==
-
-mime-types@^2.1.12, mime-types@^2.1.18, mime-types@^2.1.27, mime-types@~2.1.19:
-  version "2.1.27"
-  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f"
-  integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==
+mime-types@^2.1.12, mime-types@^2.1.18, mime-types@^2.1.27, mime-types@~2.1.19, mime-types@~2.1.24:
+  version "2.1.30"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.30.tgz#6e7be8b4c479825f85ed6326695db73f9305d62d"
+  integrity sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==
   dependencies:
-    mime-db "1.44.0"
-
-mime-types@~2.1.24:
-  version "2.1.26"
-  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06"
-  integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==
-  dependencies:
-    mime-db "1.43.0"
+    mime-db "1.47.0"
 
 mime@^2.3.1:
-  version "2.4.4"
-  resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5"
-  integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==
+  version "2.5.2"
+  resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe"
+  integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==
 
 minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.4:
   version "3.0.4"
@@ -3072,59 +3132,60 @@
   resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
   integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=
 
-mkdirp@0.5.5, mkdirp@^0.5.1:
+mkdirp@^0.5.5:
   version "0.5.5"
   resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
   integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
   dependencies:
     minimist "^1.2.5"
 
-mocha@7.2.0:
-  version "7.2.0"
-  resolved "https://registry.yarnpkg.com/mocha/-/mocha-7.2.0.tgz#01cc227b00d875ab1eed03a75106689cfed5a604"
-  integrity sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==
+mocha@8.3.2:
+  version "8.3.2"
+  resolved "https://registry.yarnpkg.com/mocha/-/mocha-8.3.2.tgz#53406f195fa86fbdebe71f8b1c6fb23221d69fcc"
+  integrity sha512-UdmISwr/5w+uXLPKspgoV7/RXZwKRTiTjJ2/AC5ZiEztIoOYdfKb19+9jNmEInzx5pBsCyJQzarAxqIGBNYJhg==
   dependencies:
-    ansi-colors "3.2.3"
+    "@ungap/promise-all-settled" "1.1.2"
+    ansi-colors "4.1.1"
     browser-stdout "1.3.1"
-    chokidar "3.3.0"
-    debug "3.2.6"
-    diff "3.5.0"
-    escape-string-regexp "1.0.5"
-    find-up "3.0.0"
-    glob "7.1.3"
+    chokidar "3.5.1"
+    debug "4.3.1"
+    diff "5.0.0"
+    escape-string-regexp "4.0.0"
+    find-up "5.0.0"
+    glob "7.1.6"
     growl "1.10.5"
     he "1.2.0"
-    js-yaml "3.13.1"
-    log-symbols "3.0.0"
+    js-yaml "4.0.0"
+    log-symbols "4.0.0"
     minimatch "3.0.4"
-    mkdirp "0.5.5"
-    ms "2.1.1"
-    node-environment-flags "1.0.6"
-    object.assign "4.1.0"
-    strip-json-comments "2.0.1"
-    supports-color "6.0.0"
-    which "1.3.1"
+    ms "2.1.3"
+    nanoid "3.1.20"
+    serialize-javascript "5.0.1"
+    strip-json-comments "3.1.1"
+    supports-color "8.1.1"
+    which "2.0.2"
     wide-align "1.1.3"
-    yargs "13.3.2"
-    yargs-parser "13.1.2"
-    yargs-unparser "1.6.0"
+    workerpool "6.1.0"
+    yargs "16.2.0"
+    yargs-parser "20.2.4"
+    yargs-unparser "2.0.0"
 
 ms@2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
   integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
 
-ms@2.1.1:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
-  integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
-
-ms@^2.1.1:
+ms@2.1.2:
   version "2.1.2"
   resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
   integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
 
-mz@^2.1.0, mz@^2.7.0:
+ms@2.1.3, ms@^2.1.1:
+  version "2.1.3"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
+  integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+
+mz@^2.1.0:
   version "2.7.0"
   resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32"
   integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==
@@ -3133,15 +3194,20 @@
     object-assign "^4.0.1"
     thenify-all "^1.0.0"
 
+nanoid@3.1.20:
+  version "3.1.20"
+  resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788"
+  integrity sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==
+
 negotiator@0.6.2:
   version "0.6.2"
   resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
   integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
 
-nise@^4.0.1:
-  version "4.0.4"
-  resolved "https://registry.yarnpkg.com/nise/-/nise-4.0.4.tgz#d73dea3e5731e6561992b8f570be9e363c4512dd"
-  integrity sha512-bTTRUNlemx6deJa+ZyoCUTRvH3liK5+N6VQZ4NIw90AgDXY6iPnsqplNFf6STcj+ePk0H/xqxnP75Lr0J0Fq3A==
+nise@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/nise/-/nise-4.1.0.tgz#8fb75a26e90b99202fa1e63f448f58efbcdedaf6"
+  integrity sha512-eQMEmGN/8arp0xsvGoQ+B1qvSkR73B1nWSCh7nOt5neMCtwcQVYQGdzQMhcNscktTsWB54xnlSQFzOAPJD8nXA==
   dependencies:
     "@sinonjs/commons" "^1.7.0"
     "@sinonjs/fake-timers" "^6.0.0"
@@ -3149,30 +3215,23 @@
     just-extend "^4.0.2"
     path-to-regexp "^1.7.0"
 
-no-case@^2.2.0:
-  version "2.3.2"
-  resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac"
-  integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==
+no-case@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d"
+  integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==
   dependencies:
-    lower-case "^1.1.1"
-
-node-environment-flags@1.0.6:
-  version "1.0.6"
-  resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.6.tgz#a30ac13621f6f7d674260a54dede048c3982c088"
-  integrity sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==
-  dependencies:
-    object.getownpropertydescriptors "^2.0.3"
-    semver "^5.7.0"
+    lower-case "^2.0.2"
+    tslib "^2.0.3"
 
 node-fetch@^2.6.0:
-  version "2.6.0"
-  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
-  integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
+  integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
 
-node-releases@^1.1.58:
-  version "1.1.58"
-  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.58.tgz#8ee20eef30fa60e52755fcc0942def5a734fe935"
-  integrity sha512-NxBudgVKiRh/2aPWMgPR7bPTX0VPmGx5QBwCtdHitnqFE5/O8DeBXuIMH1nwNnw/aMo6AjOrpsHzfY3UbUJ7yg==
+node-releases@^1.1.70:
+  version "1.1.71"
+  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.71.tgz#cb1334b179896b1c89ecfdd4b725fb7bbdfc7dbb"
+  integrity sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==
 
 normalize-package-data@^2.3.2:
   version "2.5.0"
@@ -3204,33 +3263,20 @@
   resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291"
   integrity sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=
 
-object-inspect@^1.7.0:
-  version "1.8.0"
-  resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0"
-  integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==
-
-object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1:
+object-keys@^1.0.12, object-keys@^1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
   integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
 
-object.assign@4.1.0, object.assign@^4.1.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
-  integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==
+object.assign@^4.1.0:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940"
+  integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==
   dependencies:
-    define-properties "^1.1.2"
-    function-bind "^1.1.1"
-    has-symbols "^1.0.0"
-    object-keys "^1.0.11"
-
-object.getownpropertydescriptors@^2.0.3:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649"
-  integrity sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==
-  dependencies:
+    call-bind "^1.0.0"
     define-properties "^1.1.3"
-    es-abstract "^1.17.0-next.1"
+    has-symbols "^1.0.1"
+    object-keys "^1.1.1"
 
 on-finished@^2.3.0, on-finished@~2.3.0:
   version "2.3.0"
@@ -3252,9 +3298,9 @@
   integrity sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q=
 
 open@^7.0.3:
-  version "7.0.4"
-  resolved "https://registry.yarnpkg.com/open/-/open-7.0.4.tgz#c28a9d315e5c98340bf979fdcb2e58664aa10d83"
-  integrity sha512-brSA+/yq+b08Hsr4c8fsEW2CRzk1BmfN3SAK/5VCHQ9bdoZJ4qa/+AfR0xHjlbbZUyPkUHs1b8x1RqdyZdkVqQ==
+  version "7.4.2"
+  resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321"
+  integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==
   dependencies:
     is-docker "^2.0.0"
     is-wsl "^2.1.1"
@@ -3273,12 +3319,19 @@
   integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
 
 p-limit@^2.0.0:
-  version "2.2.2"
-  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e"
-  integrity sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
+  integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
   dependencies:
     p-try "^2.0.0"
 
+p-limit@^3.0.2:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
+  integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
+  dependencies:
+    yocto-queue "^0.1.0"
+
 p-locate@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
@@ -3286,17 +3339,25 @@
   dependencies:
     p-limit "^2.0.0"
 
+p-locate@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
+  integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
+  dependencies:
+    p-limit "^3.0.2"
+
 p-try@^2.0.0:
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
   integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
 
-param-case@^2.1.1:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247"
-  integrity sha1-35T9jPZTHs915r75oIWPvHK+Ikc=
+param-case@^3.0.3:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5"
+  integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==
   dependencies:
-    no-case "^2.2.0"
+    dot-case "^3.0.4"
+    tslib "^2.0.3"
 
 parse-json@^4.0.0:
   version "4.0.0"
@@ -3330,11 +3391,24 @@
   resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
   integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
 
+pascal-case@^3.1.2:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb"
+  integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==
+  dependencies:
+    no-case "^3.0.4"
+    tslib "^2.0.3"
+
 path-exists@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
   integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
 
+path-exists@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
+  integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
+
 path-is-absolute@1.0.1, path-is-absolute@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
@@ -3364,17 +3438,17 @@
   dependencies:
     pify "^3.0.0"
 
-pathval@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0"
-  integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA=
+pathval@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d"
+  integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==
 
 performance-now@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
   integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
 
-picomatch@^2.0.4, picomatch@^2.0.7, picomatch@^2.2.2:
+picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2:
   version "2.2.2"
   resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
   integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
@@ -3384,20 +3458,19 @@
   resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
   integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
 
-polyfills-loader@^1.6.1:
-  version "1.6.1"
-  resolved "https://registry.yarnpkg.com/polyfills-loader/-/polyfills-loader-1.6.1.tgz#134ab74b9a6160efb4d72066a5150bfb2228fad3"
-  integrity sha512-GK3jZGLy9nApfRYfHrrO4RYkBkpjiXUVWVdp169g4Y8HV+ZazrGQX46tNpbwP0dtrgHgADyJvZYPfdFuooHy5Q==
+polyfills-loader@^1.6.1, polyfills-loader@^1.7.4:
+  version "1.7.6"
+  resolved "https://registry.yarnpkg.com/polyfills-loader/-/polyfills-loader-1.7.6.tgz#5cff98bfc9689cf10e44bdd32f498cfeb4374c51"
+  integrity sha512-AiLIgmGFmzcvsqewyKsqWb7H8CnWNTSQBoM0u+Mauzmp0DsjObXmnZdeqvTn0HNwc1wYHHTOta82WjSjG341eQ==
   dependencies:
-    "@babel/core" "^7.9.0"
-    "@open-wc/building-utils" "^2.18.0"
+    "@babel/core" "^7.11.1"
+    "@open-wc/building-utils" "^2.18.3"
     "@webcomponents/webcomponentsjs" "^2.4.0"
     abortcontroller-polyfill "^1.4.0"
     core-js-bundle "^3.6.0"
     deepmerge "^4.2.2"
     dynamic-import-polyfill "^0.1.1"
     es-module-shims "^0.4.6"
-    html-minifier "^4.0.0"
     intersection-observer "^0.7.0"
     parse5 "^5.1.1"
     regenerator-runtime "^0.13.3"
@@ -3407,13 +3480,13 @@
     whatwg-fetch "^3.0.0"
 
 portfinder@^1.0.21:
-  version "1.0.26"
-  resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.26.tgz#475658d56ca30bed72ac7f1378ed350bd1b64e70"
-  integrity sha512-Xi7mKxJHHMI3rIUrnm/jjUgwhbYMkp/XKEcZX3aG4BrumLpq3nmoQMX+ClYnDZnZ/New7IatC1no5RX0zo1vXQ==
+  version "1.0.28"
+  resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778"
+  integrity sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==
   dependencies:
     async "^2.6.2"
     debug "^3.1.1"
-    mkdirp "^0.5.1"
+    mkdirp "^0.5.5"
 
 pseudomap@^1.0.2:
   version "1.0.2"
@@ -3453,6 +3526,13 @@
   resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
   integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
 
+randombytes@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
+  integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
+  dependencies:
+    safe-buffer "^5.1.0"
+
 range-parser@^1.2.0:
   version "1.2.1"
   resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
@@ -3485,19 +3565,12 @@
     normalize-package-data "^2.3.2"
     path-type "^3.0.0"
 
-readdirp@~3.2.0:
-  version "3.2.0"
-  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.2.0.tgz#c30c33352b12c96dfb4b895421a49fd5a9593839"
-  integrity sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==
+readdirp@~3.5.0:
+  version "3.5.0"
+  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e"
+  integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==
   dependencies:
-    picomatch "^2.0.4"
-
-readdirp@~3.3.0:
-  version "3.3.0"
-  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.3.0.tgz#984458d13a1e42e2e9f5841b129e162f369aff17"
-  integrity sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==
-  dependencies:
-    picomatch "^2.0.7"
+    picomatch "^2.2.1"
 
 reduce-flatten@^2.0.0:
   version "2.0.0"
@@ -3512,14 +3585,14 @@
     regenerate "^1.4.0"
 
 regenerate@^1.4.0:
-  version "1.4.1"
-  resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.1.tgz#cad92ad8e6b591773485fbe05a485caf4f457e6f"
-  integrity sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A==
+  version "1.4.2"
+  resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a"
+  integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==
 
-regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4:
-  version "0.13.5"
-  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697"
-  integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==
+regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.7:
+  version "0.13.7"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
+  integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
 
 regenerator-transform@^0.14.2:
   version "0.14.5"
@@ -3528,10 +3601,10 @@
   dependencies:
     "@babel/runtime" "^7.8.4"
 
-regexpu-core@^4.7.0:
-  version "4.7.0"
-  resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.0.tgz#fcbf458c50431b0bb7b45d6967b8192d91f3d938"
-  integrity sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ==
+regexpu-core@^4.7.1:
+  version "4.7.1"
+  resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.1.tgz#2dea5a9a07233298fbf0db91fa9abc4c6e0f8ad6"
+  integrity sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==
   dependencies:
     regenerate "^1.4.0"
     regenerate-unicode-properties "^8.2.0"
@@ -3546,9 +3619,9 @@
   integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==
 
 regjsparser@^0.6.4:
-  version "0.6.4"
-  resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272"
-  integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==
+  version "0.6.9"
+  resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.9.tgz#b489eef7c9a2ce43727627011429cf833a7183e6"
+  integrity sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ==
   dependencies:
     jsesc "~0.5.0"
 
@@ -3611,17 +3684,18 @@
     http-errors "~1.6.2"
     path-is-absolute "1.0.1"
 
-resolve@^1.10.0, resolve@^1.11.1, resolve@^1.14.2, resolve@^1.3.2:
-  version "1.17.0"
-  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444"
-  integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==
+resolve@^1.10.0, resolve@^1.14.2, resolve@^1.19.0:
+  version "1.20.0"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
+  integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
   dependencies:
+    is-core-module "^2.2.0"
     path-parse "^1.0.6"
 
 rfdc@^1.1.4:
-  version "1.1.4"
-  resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.1.4.tgz#ba72cc1367a0ccd9cf81a870b3b58bd3ad07f8c2"
-  integrity sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b"
+  integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==
 
 rimraf@^2.6.0:
   version "2.7.1"
@@ -3638,23 +3712,18 @@
     glob "^7.1.3"
 
 rollup@^2.7.2:
-  version "2.18.2"
-  resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.18.2.tgz#886ac6e4549e493df106c3e2580c89aeb997be25"
-  integrity sha512-+mzyZhL9ZyLB3eHBISxRNTep9Z2qCuwXzAYkUbFyz7yNKaKH03MFKeiGOS1nv2uvPgDb4ASKv+FiS5mC4h5IFQ==
+  version "2.44.0"
+  resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.44.0.tgz#8da324d1c4fd12beef9ae6e12f4068265b6d95eb"
+  integrity sha512-rGSF4pLwvuaH/x4nAS+zP6UNn5YUDWf/TeEU5IoXSZKBbKRNTCI3qMnYXKZgrC0D2KzS2baiOZt1OlqhMu5rnQ==
   optionalDependencies:
-    fsevents "~2.1.2"
+    fsevents "~2.3.1"
 
 safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
   version "5.1.2"
   resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
   integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
 
-safe-buffer@^5.0.1:
-  version "5.2.0"
-  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
-  integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
-
-safe-buffer@^5.1.2:
+safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2:
   version "5.2.1"
   resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
   integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
@@ -3664,7 +3733,7 @@
   resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
   integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
 
-"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.7.0:
+"semver@2 || 3 || 4 || 5":
   version "5.7.1"
   resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
   integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
@@ -3674,20 +3743,24 @@
   resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
   integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
 
-semver@^6.0.0:
+semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
   version "6.3.0"
   resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
   integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
 
 semver@^7.3.2:
-  version "7.3.2"
-  resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"
-  integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==
+  version "7.3.5"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
+  integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
+  dependencies:
+    lru-cache "^6.0.0"
 
-set-blocking@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
-  integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
+serialize-javascript@5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4"
+  integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==
+  dependencies:
+    randombytes "^2.1.0"
 
 setprototypeof@1.1.0:
   version "1.1.0"
@@ -3709,17 +3782,16 @@
   resolved "https://registry.yarnpkg.com/shady-css-scoped-element/-/shady-css-scoped-element-0.0.2.tgz#c538fcfe2317e979cd02dfec533898b95b4ea8fe"
   integrity sha512-Dqfl70x6JiwYDujd33ZTbtCK0t52E7+H2swdWQNSTzfsolSa6LJHnTpN4T9OpJJEq4bxuzHRLFO9RBcy/UfrMQ==
 
-sinon@^9.0.2:
-  version "9.0.2"
-  resolved "https://registry.yarnpkg.com/sinon/-/sinon-9.0.2.tgz#b9017e24633f4b1c98dfb6e784a5f0509f5fd85d"
-  integrity sha512-0uF8Q/QHkizNUmbK3LRFqx5cpTttEVXudywY9Uwzy8bTfZUhljZ7ARzSxnRHWYWtVTeh4Cw+tTb3iU21FQVO9A==
+sinon@^10.0.0:
+  version "10.0.0"
+  resolved "https://registry.yarnpkg.com/sinon/-/sinon-10.0.0.tgz#52279f97e35646ff73d23207d0307977c9b81430"
+  integrity sha512-XAn5DxtGVJBlBWYrcYKEhWCz7FLwZGdyvANRyK06419hyEpdT0dMc5A8Vcxg5SCGHc40CsqoKsc1bt1CbJPfNw==
   dependencies:
-    "@sinonjs/commons" "^1.7.2"
+    "@sinonjs/commons" "^1.8.1"
     "@sinonjs/fake-timers" "^6.0.1"
-    "@sinonjs/formatio" "^5.0.1"
-    "@sinonjs/samsam" "^5.0.3"
+    "@sinonjs/samsam" "^5.3.1"
     diff "^4.0.2"
-    nise "^4.0.1"
+    nise "^4.1.0"
     supports-color "^7.1.0"
 
 socket.io-adapter@~1.1.0:
@@ -3808,14 +3880,9 @@
     spdx-license-ids "^3.0.0"
 
 spdx-license-ids@^3.0.0:
-  version "3.0.5"
-  resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654"
-  integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==
-
-sprintf-js@~1.0.2:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
-  integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
+  version "3.0.7"
+  resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz#e9c18a410e5ed7e12442a549fbd8afa767038d65"
+  integrity sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==
 
 sshpk@^1.7.0:
   version "1.16.1"
@@ -3856,30 +3923,14 @@
     is-fullwidth-code-point "^2.0.0"
     strip-ansi "^4.0.0"
 
-string-width@^3.0.0, string-width@^3.1.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
-  integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
+string-width@^4.1.0, string-width@^4.2.0:
+  version "4.2.2"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5"
+  integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==
   dependencies:
-    emoji-regex "^7.0.1"
-    is-fullwidth-code-point "^2.0.0"
-    strip-ansi "^5.1.0"
-
-string.prototype.trimend@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913"
-  integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==
-  dependencies:
-    define-properties "^1.1.3"
-    es-abstract "^1.17.5"
-
-string.prototype.trimstart@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54"
-  integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==
-  dependencies:
-    define-properties "^1.1.3"
-    es-abstract "^1.17.5"
+    emoji-regex "^8.0.0"
+    is-fullwidth-code-point "^3.0.0"
+    strip-ansi "^6.0.0"
 
 strip-ansi@^4.0.0:
   version "4.0.0"
@@ -3888,29 +3939,36 @@
   dependencies:
     ansi-regex "^3.0.0"
 
-strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
+strip-ansi@^5.2.0:
   version "5.2.0"
   resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
   integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
   dependencies:
     ansi-regex "^4.1.0"
 
+strip-ansi@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532"
+  integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==
+  dependencies:
+    ansi-regex "^5.0.0"
+
 strip-bom@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
   integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=
 
-strip-json-comments@2.0.1:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
-  integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
+strip-json-comments@3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
+  integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
 
-supports-color@6.0.0:
-  version "6.0.0"
-  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a"
-  integrity sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==
+supports-color@8.1.1:
+  version "8.1.1"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
+  integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
   dependencies:
-    has-flag "^3.0.0"
+    has-flag "^4.0.0"
 
 supports-color@^5.3.0:
   version "5.5.0"
@@ -3920,28 +3978,28 @@
     has-flag "^3.0.0"
 
 supports-color@^7.1.0:
-  version "7.1.0"
-  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1"
-  integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
+  integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
   dependencies:
     has-flag "^4.0.0"
 
-systemjs@^6.3.1:
-  version "6.3.3"
-  resolved "https://registry.yarnpkg.com/systemjs/-/systemjs-6.3.3.tgz#c0f2bec5cc72d0b36a8b971b1fa32bfc828b50d4"
-  integrity sha512-djQ6mZ4/cWKnVnhAWvr/4+5r7QHnC7WiA8sS9VuYRdEv3wYZYTIIQv8zPT79PdDSUwfX3bgvu5mZ8eTyLm2YQA==
+systemjs@^6.3.1, systemjs@^6.8.3:
+  version "6.8.3"
+  resolved "https://registry.yarnpkg.com/systemjs/-/systemjs-6.8.3.tgz#67e27f49242e9d81c2b652b204ae54e8bfcc75a3"
+  integrity sha512-UcTY+FEA1B7e+bpJk1TI+a9Na6LG7wFEqW7ED16cLqLuQfI/9Ri0rsXm3tKlIgNoHyLHZycjdAOijzNbzelgwA==
 
-table-layout@^1.0.0:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-1.0.1.tgz#8411181ee951278ad0638aea2f779a9ce42894f9"
-  integrity sha512-dEquqYNJiGwY7iPfZ3wbXDI944iqanTSchrACLL2nOB+1r+h1Nzu2eH+DuPPvWvm5Ry7iAPeFlgEtP5bIp5U7Q==
+table-layout@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-1.0.2.tgz#c4038a1853b0136d63365a734b6931cf4fad4a04"
+  integrity sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==
   dependencies:
     array-back "^4.0.1"
     deep-extend "~0.6.0"
     typical "^5.2.0"
     wordwrapjs "^4.0.0"
 
-terser@^4.6.7:
+terser@^4.6.3, terser@^4.6.7:
   version "4.8.0"
   resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17"
   integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==
@@ -4019,9 +4077,14 @@
     punycode "^2.1.0"
 
 tslib@^1.11.1:
-  version "1.13.0"
-  resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
-  integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
+  version "1.14.1"
+  resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
+  integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
+
+tslib@^2.0.3:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c"
+  integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==
 
 tsscmp@1.0.6:
   version "1.0.6"
@@ -4058,16 +4121,11 @@
   resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4"
   integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==
 
-typical@^5.0.0, typical@^5.2.0:
+typical@^5.2.0:
   version "5.2.0"
   resolved "https://registry.yarnpkg.com/typical/-/typical-5.2.0.tgz#4daaac4f2b5315460804f0acf6cb69c52bb93066"
   integrity sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==
 
-uglify-js@^3.5.1:
-  version "3.10.0"
-  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.10.0.tgz#397a7e6e31ce820bfd1cb55b804ee140c587a9e7"
-  integrity sha512-Esj5HG5WAyrLIdYU74Z3JdG2PxdIusvj6IWHMtlyESxc7kcDz7zYlYjpnSokn1UbpV0d/QX9fan7gkCNd/9BQA==
-
 ultron@~1.1.0:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c"
@@ -4106,15 +4164,10 @@
   resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
   integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=
 
-upper-case@^1.1.1:
-  version "1.1.3"
-  resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598"
-  integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=
-
 uri-js@^4.2.2:
-  version "4.2.2"
-  resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
-  integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
+  version "4.4.1"
+  resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
+  integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
   dependencies:
     punycode "^2.1.0"
 
@@ -4173,12 +4226,12 @@
   resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
   integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==
 
-whatwg-fetch@^3.0.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.1.0.tgz#49d630cdfa308dba7f2819d49d09364f540dbcc6"
-  integrity sha512-pgmbsVWKpH9GxLXZmtdowDIqtb/rvPyjjQv3z9wLcmgWKFHilKnZD3ldgrOlwJoPGOUluQsRPWd52yVkPfmI1A==
+whatwg-fetch@^3.0.0, whatwg-fetch@^3.5.0:
+  version "3.6.2"
+  resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c"
+  integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==
 
-whatwg-url@^7.0.0:
+whatwg-url@^7.0.0, whatwg-url@^7.1.0:
   version "7.1.0"
   resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06"
   integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==
@@ -4187,12 +4240,14 @@
     tr46 "^1.0.1"
     webidl-conversions "^4.0.2"
 
-which-module@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
-  integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
+which@2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
+  integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
+  dependencies:
+    isexe "^2.0.0"
 
-which@1.3.1, which@^1.2.1:
+which@^1.2.1:
   version "1.3.1"
   resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
   integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
@@ -4212,21 +4267,26 @@
   integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc=
 
 wordwrapjs@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/wordwrapjs/-/wordwrapjs-4.0.0.tgz#9aa9394155993476e831ba8e59fb5795ebde6800"
-  integrity sha512-Svqw723a3R34KvsMgpjFBYCgNOSdcW3mQFK4wIfhGQhtaFVOJmdYoXgi63ne3dTlWgatVcUc7t4HtQ/+bUVIzQ==
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/wordwrapjs/-/wordwrapjs-4.0.1.tgz#d9790bccfb110a0fc7836b5ebce0937b37a8b98f"
+  integrity sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==
   dependencies:
     reduce-flatten "^2.0.0"
-    typical "^5.0.0"
+    typical "^5.2.0"
 
-wrap-ansi@^5.1.0:
-  version "5.1.0"
-  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09"
-  integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==
+workerpool@6.1.0:
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.1.0.tgz#a8e038b4c94569596852de7a8ea4228eefdeb37b"
+  integrity sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==
+
+wrap-ansi@^7.0.0:
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
+  integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
   dependencies:
-    ansi-styles "^3.2.0"
-    string-width "^3.0.0"
-    strip-ansi "^5.0.0"
+    ansi-styles "^4.0.0"
+    string-width "^4.1.0"
+    strip-ansi "^6.0.0"
 
 wrappy@1:
   version "1.0.2"
@@ -4247,10 +4307,10 @@
   resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e"
   integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=
 
-y18n@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
-  integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
+y18n@^5.0.5:
+  version "5.0.8"
+  resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
+  integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
 
 yallist@^2.1.2:
   version "2.1.2"
@@ -4262,38 +4322,43 @@
   resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
   integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
 
-yargs-parser@13.1.2, yargs-parser@^13.1.2:
-  version "13.1.2"
-  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38"
-  integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==
-  dependencies:
-    camelcase "^5.0.0"
-    decamelize "^1.2.0"
+yallist@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
+  integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
 
-yargs-unparser@1.6.0:
-  version "1.6.0"
-  resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f"
-  integrity sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==
-  dependencies:
-    flat "^4.1.0"
-    lodash "^4.17.15"
-    yargs "^13.3.0"
+yargs-parser@20.2.4:
+  version "20.2.4"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54"
+  integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==
 
-yargs@13.3.2, yargs@^13.3.0:
-  version "13.3.2"
-  resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd"
-  integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==
+yargs-parser@^20.2.2:
+  version "20.2.7"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.7.tgz#61df85c113edfb5a7a4e36eb8aa60ef423cbc90a"
+  integrity sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==
+
+yargs-unparser@2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb"
+  integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==
   dependencies:
-    cliui "^5.0.0"
-    find-up "^3.0.0"
-    get-caller-file "^2.0.1"
+    camelcase "^6.0.0"
+    decamelize "^4.0.0"
+    flat "^5.0.2"
+    is-plain-obj "^2.1.0"
+
+yargs@16.2.0:
+  version "16.2.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
+  integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
+  dependencies:
+    cliui "^7.0.2"
+    escalade "^3.1.1"
+    get-caller-file "^2.0.5"
     require-directory "^2.1.1"
-    require-main-filename "^2.0.0"
-    set-blocking "^2.0.0"
-    string-width "^3.0.0"
-    which-module "^2.0.0"
-    y18n "^4.0.0"
-    yargs-parser "^13.1.2"
+    string-width "^4.2.0"
+    y18n "^5.0.5"
+    yargs-parser "^20.2.2"
 
 yeast@0.1.2:
   version "0.1.2"
@@ -4304,3 +4369,8 @@
   version "1.2.1"
   resolved "https://registry.yarnpkg.com/ylru/-/ylru-1.2.1.tgz#f576b63341547989c1de7ba288760923b27fe84f"
   integrity sha512-faQrqNMzcPCHGVC2aaOINk13K+aaBDUPjGWl0teOXywElLjyVAB6Oe2jj62jHYtwsU49jXhScYbvPENK+6zAvQ==
+
+yocto-queue@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
+  integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
diff --git a/tools/node_tools/package.json b/tools/node_tools/package.json
index 2f33078..6e29299 100644
--- a/tools/node_tools/package.json
+++ b/tools/node_tools/package.json
@@ -3,8 +3,8 @@
   "description": "Gerrit Build Tools",
   "browser": false,
   "dependencies": {
-    "@bazel/rollup": "^3.2.3",
-    "@bazel/typescript": "^3.2.3",
+    "@bazel/rollup": "^3.4.0",
+    "@bazel/typescript": "^3.4.0",
     "@types/node": "^10.17.12",
     "@types/parse5": "^4.0.0",
     "@types/parse5-html-rewriting-stream": "^5.1.2",
diff --git a/tools/node_tools/yarn.lock b/tools/node_tools/yarn.lock
index abb54b0..b8ac5fb 100644
--- a/tools/node_tools/yarn.lock
+++ b/tools/node_tools/yarn.lock
@@ -492,15 +492,15 @@
     lodash "^4.17.13"
     to-fast-properties "^2.0.0"
 
-"@bazel/rollup@^3.2.3":
-  version "3.2.3"
-  resolved "https://registry.yarnpkg.com/@bazel/rollup/-/rollup-3.2.3.tgz#eb6b17f89da5d38b035a6d59a99000f2d5ada667"
-  integrity sha512-7PmJqekk92OaiwwEN3dYsp5qbZX8cqr0WkFUiaM3FBsNYVoN/rdh+VxQJWTuDGLjWiHxLwE95YwVHcvwerSrCg==
+"@bazel/rollup@^3.4.0":
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/@bazel/rollup/-/rollup-3.4.0.tgz#cdecb2b90535ef51fb3d56cc8bc19996918bac1a"
+  integrity sha512-QKnttbYyEQjRbWrOlkH2JuDnSww+9K7Ppil91zBTtr/qYTGW9XO0v7Ft3cs30s2NIWSGIuKj9/N5as+Uyratrw==
 
-"@bazel/typescript@^3.2.3":
-  version "3.2.3"
-  resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-3.2.3.tgz#6e40bdb7c5294e588bac3b7d1269e58b98a1856c"
-  integrity sha512-Q1Yin/AYdh9yrkSJo3H6nVn6mMaohr5syjLd0Df0w7WI4zerdJTxrY5nhoWZwO/S1rPj8/MedDwZudCqPDeDMA==
+"@bazel/typescript@^3.4.0":
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-3.4.0.tgz#031d989682ff8605ed8745f31448c2f76a1b653a"
+  integrity sha512-XlWrlQnsdQHTwsliUAf4mySHOgqRY2S57LKG2rKRjm+a015Lzlmxo6jRQaxjr68UmuhmlklRw0WfCFxdR81AvQ==
   dependencies:
     protobufjs "6.8.8"
     semver "5.6.0"
diff --git a/yarn.lock b/yarn.lock
index d18d5fd..ead8dbf 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,513 +2,537 @@
 # yarn lockfile v1
 
 
-"@babel/code-frame@^7.0.0":
-  version "7.0.0"
-  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8"
-  integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==
+"@babel/code-frame@7.12.11", "@babel/code-frame@^7.0.0":
+  version "7.12.11"
+  resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz"
+  integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==
   dependencies:
-    "@babel/highlight" "^7.0.0"
+    "@babel/highlight" "^7.10.4"
+
+"@babel/code-frame@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658"
+  integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==
+  dependencies:
+    "@babel/highlight" "^7.12.13"
+
+"@babel/compat-data@^7.13.12", "@babel/compat-data@^7.13.8":
+  version "7.13.15"
+  resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.13.15.tgz#7e8eea42d0b64fda2b375b22d06c605222e848f4"
+  integrity sha512-ltnibHKR1VnrU4ymHyQ/CXtNXI6yZC0oJThyW78Hft8XndANwi+9H+UIklBDraIjFEJzw8wmcM427oDd9KS5wA==
 
 "@babel/core@^7.0.0":
-  version "7.5.4"
-  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.5.4.tgz#4c32df7ad5a58e9ea27ad025c11276324e0b4ddd"
-  integrity sha512-+DaeBEpYq6b2+ZmHx3tHspC+ZRflrvLqwfv8E3hNr5LVQoyBnL8RPKSBCg+rK2W2My9PWlujBiqd0ZPsR9Q6zQ==
+  version "7.13.15"
+  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.13.15.tgz#a6d40917df027487b54312202a06812c4f7792d0"
+  integrity sha512-6GXmNYeNjS2Uz+uls5jalOemgIhnTMeaXo+yBUA72kC2uX/8VW6XyhVIo2L8/q0goKQA3EVKx0KOQpVKSeWadQ==
   dependencies:
-    "@babel/code-frame" "^7.0.0"
-    "@babel/generator" "^7.5.0"
-    "@babel/helpers" "^7.5.4"
-    "@babel/parser" "^7.5.0"
-    "@babel/template" "^7.4.4"
-    "@babel/traverse" "^7.5.0"
-    "@babel/types" "^7.5.0"
-    convert-source-map "^1.1.0"
+    "@babel/code-frame" "^7.12.13"
+    "@babel/generator" "^7.13.9"
+    "@babel/helper-compilation-targets" "^7.13.13"
+    "@babel/helper-module-transforms" "^7.13.14"
+    "@babel/helpers" "^7.13.10"
+    "@babel/parser" "^7.13.15"
+    "@babel/template" "^7.12.13"
+    "@babel/traverse" "^7.13.15"
+    "@babel/types" "^7.13.14"
+    convert-source-map "^1.7.0"
     debug "^4.1.0"
-    json5 "^2.1.0"
-    lodash "^4.17.11"
-    resolve "^1.3.2"
-    semver "^5.4.1"
+    gensync "^1.0.0-beta.2"
+    json5 "^2.1.2"
+    semver "^6.3.0"
     source-map "^0.5.0"
 
-"@babel/generator@^7.0.0-beta.42", "@babel/generator@^7.5.0":
-  version "7.5.0"
-  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.5.0.tgz#f20e4b7a91750ee8b63656073d843d2a736dca4a"
-  integrity sha512-1TTVrt7J9rcG5PMjvO7VEG3FrEoEJNHxumRq66GemPmzboLWtIjjcJgk8rokuAS7IiRSpgVSu5Vb9lc99iJkOA==
+"@babel/generator@^7.0.0-beta.42", "@babel/generator@^7.13.9":
+  version "7.13.9"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.13.9.tgz#3a7aa96f9efb8e2be42d38d80e2ceb4c64d8de39"
+  integrity sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==
   dependencies:
-    "@babel/types" "^7.5.0"
+    "@babel/types" "^7.13.0"
     jsesc "^2.5.1"
-    lodash "^4.17.11"
     source-map "^0.5.0"
-    trim-right "^1.0.1"
 
-"@babel/helper-annotate-as-pure@^7.0.0":
-  version "7.0.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32"
-  integrity sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==
+"@babel/helper-annotate-as-pure@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.13.tgz#0f58e86dfc4bb3b1fcd7db806570e177d439b6ab"
+  integrity sha512-7YXfX5wQ5aYM/BOlbSccHDbuXXFPxeoUmfWtz8le2yTkTZc+BxsiEnENFoi2SlmA8ewDkG2LgIMIVzzn2h8kfw==
   dependencies:
-    "@babel/types" "^7.0.0"
+    "@babel/types" "^7.12.13"
 
-"@babel/helper-builder-binary-assignment-operator-visitor@^7.1.0":
-  version "7.1.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz#6b69628dfe4087798e0c4ed98e3d4a6b2fbd2f5f"
-  integrity sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==
+"@babel/helper-builder-binary-assignment-operator-visitor@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.12.13.tgz#6bc20361c88b0a74d05137a65cac8d3cbf6f61fc"
+  integrity sha512-CZOv9tGphhDRlVjVkAgm8Nhklm9RzSmWpX2my+t7Ua/KT616pEzXsQCjinzvkRvHWJ9itO4f296efroX23XCMA==
   dependencies:
-    "@babel/helper-explode-assignable-expression" "^7.1.0"
-    "@babel/types" "^7.0.0"
+    "@babel/helper-explode-assignable-expression" "^7.12.13"
+    "@babel/types" "^7.12.13"
 
-"@babel/helper-call-delegate@^7.4.4":
-  version "7.4.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz#87c1f8ca19ad552a736a7a27b1c1fcf8b1ff1f43"
-  integrity sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ==
+"@babel/helper-compilation-targets@^7.13.13", "@babel/helper-compilation-targets@^7.13.8":
+  version "7.13.13"
+  resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.13.tgz#2b2972a0926474853f41e4adbc69338f520600e5"
+  integrity sha512-q1kcdHNZehBwD9jYPh3WyXcsFERi39X4I59I3NadciWtNDyZ6x+GboOxncFK0kXlKIv6BJm5acncehXWUjWQMQ==
   dependencies:
-    "@babel/helper-hoist-variables" "^7.4.4"
-    "@babel/traverse" "^7.4.4"
-    "@babel/types" "^7.4.4"
+    "@babel/compat-data" "^7.13.12"
+    "@babel/helper-validator-option" "^7.12.17"
+    browserslist "^4.14.5"
+    semver "^6.3.0"
 
-"@babel/helper-define-map@^7.4.4":
-  version "7.4.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.4.4.tgz#6969d1f570b46bdc900d1eba8e5d59c48ba2c12a"
-  integrity sha512-IX3Ln8gLhZpSuqHJSnTNBWGDE9kdkTEWl21A/K7PQ00tseBwbqCHTvNLHSBd9M0R5rER4h5Rsvj9vw0R5SieBg==
+"@babel/helper-create-regexp-features-plugin@^7.12.13":
+  version "7.12.17"
+  resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.17.tgz#a2ac87e9e319269ac655b8d4415e94d38d663cb7"
+  integrity sha512-p2VGmBu9oefLZ2nQpgnEnG0ZlRPvL8gAGvPUMQwUdaE8k49rOMuZpOwdQoy5qJf6K8jL3bcAMhVUlHAjIgJHUg==
   dependencies:
-    "@babel/helper-function-name" "^7.1.0"
-    "@babel/types" "^7.4.4"
-    lodash "^4.17.11"
+    "@babel/helper-annotate-as-pure" "^7.12.13"
+    regexpu-core "^4.7.1"
 
-"@babel/helper-explode-assignable-expression@^7.1.0":
-  version "7.1.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz#537fa13f6f1674df745b0c00ec8fe4e99681c8f6"
-  integrity sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==
+"@babel/helper-explode-assignable-expression@^7.12.13":
+  version "7.13.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.13.0.tgz#17b5c59ff473d9f956f40ef570cf3a76ca12657f"
+  integrity sha512-qS0peLTDP8kOisG1blKbaoBg/o9OSa1qoumMjTK5pM+KDTtpxpsiubnCGP34vK8BXGcb2M9eigwgvoJryrzwWA==
   dependencies:
-    "@babel/traverse" "^7.1.0"
-    "@babel/types" "^7.0.0"
+    "@babel/types" "^7.13.0"
 
-"@babel/helper-function-name@^7.1.0":
-  version "7.1.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53"
-  integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==
+"@babel/helper-function-name@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz#93ad656db3c3c2232559fd7b2c3dbdcbe0eb377a"
+  integrity sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==
   dependencies:
-    "@babel/helper-get-function-arity" "^7.0.0"
-    "@babel/template" "^7.1.0"
-    "@babel/types" "^7.0.0"
+    "@babel/helper-get-function-arity" "^7.12.13"
+    "@babel/template" "^7.12.13"
+    "@babel/types" "^7.12.13"
 
-"@babel/helper-get-function-arity@^7.0.0":
-  version "7.0.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3"
-  integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==
+"@babel/helper-get-function-arity@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz#bc63451d403a3b3082b97e1d8b3fe5bd4091e583"
+  integrity sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==
   dependencies:
-    "@babel/types" "^7.0.0"
+    "@babel/types" "^7.12.13"
 
-"@babel/helper-hoist-variables@^7.4.4":
-  version "7.4.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz#0298b5f25c8c09c53102d52ac4a98f773eb2850a"
-  integrity sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w==
+"@babel/helper-member-expression-to-functions@^7.13.12":
+  version "7.13.12"
+  resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz#dfe368f26d426a07299d8d6513821768216e6d72"
+  integrity sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw==
   dependencies:
-    "@babel/types" "^7.4.4"
+    "@babel/types" "^7.13.12"
 
-"@babel/helper-member-expression-to-functions@^7.0.0":
-  version "7.0.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz#8cd14b0a0df7ff00f009e7d7a436945f47c7a16f"
-  integrity sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg==
+"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.13.12":
+  version "7.13.12"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz#c6a369a6f3621cb25da014078684da9196b61977"
+  integrity sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA==
   dependencies:
-    "@babel/types" "^7.0.0"
+    "@babel/types" "^7.13.12"
 
-"@babel/helper-module-imports@^7.0.0":
-  version "7.0.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d"
-  integrity sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==
+"@babel/helper-module-transforms@^7.13.0", "@babel/helper-module-transforms@^7.13.14":
+  version "7.13.14"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.13.14.tgz#e600652ba48ccb1641775413cb32cfa4e8b495ef"
+  integrity sha512-QuU/OJ0iAOSIatyVZmfqB0lbkVP0kDRiKj34xy+QNsnVZi/PA6BoSoreeqnxxa9EHFAIL0R9XOaAR/G9WlIy5g==
   dependencies:
-    "@babel/types" "^7.0.0"
+    "@babel/helper-module-imports" "^7.13.12"
+    "@babel/helper-replace-supers" "^7.13.12"
+    "@babel/helper-simple-access" "^7.13.12"
+    "@babel/helper-split-export-declaration" "^7.12.13"
+    "@babel/helper-validator-identifier" "^7.12.11"
+    "@babel/template" "^7.12.13"
+    "@babel/traverse" "^7.13.13"
+    "@babel/types" "^7.13.14"
 
-"@babel/helper-module-transforms@^7.1.0":
-  version "7.4.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.4.4.tgz#96115ea42a2f139e619e98ed46df6019b94414b8"
-  integrity sha512-3Z1yp8TVQf+B4ynN7WoHPKS8EkdTbgAEy0nU0rs/1Kw4pDgmvYH3rz3aI11KgxKCba2cn7N+tqzV1mY2HMN96w==
+"@babel/helper-optimise-call-expression@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz#5c02d171b4c8615b1e7163f888c1c81c30a2aaea"
+  integrity sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==
   dependencies:
-    "@babel/helper-module-imports" "^7.0.0"
-    "@babel/helper-simple-access" "^7.1.0"
-    "@babel/helper-split-export-declaration" "^7.4.4"
-    "@babel/template" "^7.4.4"
-    "@babel/types" "^7.4.4"
-    lodash "^4.17.11"
+    "@babel/types" "^7.12.13"
 
-"@babel/helper-optimise-call-expression@^7.0.0":
-  version "7.0.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz#a2920c5702b073c15de51106200aa8cad20497d5"
-  integrity sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==
+"@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.8.0":
+  version "7.13.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz#806526ce125aed03373bc416a828321e3a6a33af"
+  integrity sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==
+
+"@babel/helper-remap-async-to-generator@^7.13.0":
+  version "7.13.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.13.0.tgz#376a760d9f7b4b2077a9dd05aa9c3927cadb2209"
+  integrity sha512-pUQpFBE9JvC9lrQbpX0TmeNIy5s7GnZjna2lhhcHC7DzgBs6fWn722Y5cfwgrtrqc7NAJwMvOa0mKhq6XaE4jg==
   dependencies:
-    "@babel/types" "^7.0.0"
+    "@babel/helper-annotate-as-pure" "^7.12.13"
+    "@babel/helper-wrap-function" "^7.13.0"
+    "@babel/types" "^7.13.0"
 
-"@babel/helper-plugin-utils@^7.0.0":
-  version "7.0.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250"
-  integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==
-
-"@babel/helper-regex@^7.0.0", "@babel/helper-regex@^7.4.4":
-  version "7.4.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.4.4.tgz#a47e02bc91fb259d2e6727c2a30013e3ac13c4a2"
-  integrity sha512-Y5nuB/kESmR3tKjU8Nkn1wMGEx1tjJX076HBMeL3XLQCu6vA/YRzuTW0bbb+qRnXvQGn+d6Rx953yffl8vEy7Q==
+"@babel/helper-replace-supers@^7.12.13", "@babel/helper-replace-supers@^7.13.0", "@babel/helper-replace-supers@^7.13.12":
+  version "7.13.12"
+  resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.13.12.tgz#6442f4c1ad912502481a564a7386de0c77ff3804"
+  integrity sha512-Gz1eiX+4yDO8mT+heB94aLVNCL+rbuT2xy4YfyNqu8F+OI6vMvJK891qGBTqL9Uc8wxEvRW92Id6G7sDen3fFw==
   dependencies:
-    lodash "^4.17.11"
+    "@babel/helper-member-expression-to-functions" "^7.13.12"
+    "@babel/helper-optimise-call-expression" "^7.12.13"
+    "@babel/traverse" "^7.13.0"
+    "@babel/types" "^7.13.12"
 
-"@babel/helper-remap-async-to-generator@^7.1.0":
-  version "7.1.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz#361d80821b6f38da75bd3f0785ece20a88c5fe7f"
-  integrity sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==
+"@babel/helper-simple-access@^7.13.12":
+  version "7.13.12"
+  resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz#dd6c538afb61819d205a012c31792a39c7a5eaf6"
+  integrity sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA==
   dependencies:
-    "@babel/helper-annotate-as-pure" "^7.0.0"
-    "@babel/helper-wrap-function" "^7.1.0"
-    "@babel/template" "^7.1.0"
-    "@babel/traverse" "^7.1.0"
-    "@babel/types" "^7.0.0"
+    "@babel/types" "^7.13.12"
 
-"@babel/helper-replace-supers@^7.1.0", "@babel/helper-replace-supers@^7.4.4":
-  version "7.4.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.4.4.tgz#aee41783ebe4f2d3ab3ae775e1cc6f1a90cefa27"
-  integrity sha512-04xGEnd+s01nY1l15EuMS1rfKktNF+1CkKmHoErDppjAAZL+IUBZpzT748x262HF7fibaQPhbvWUl5HeSt1EXg==
+"@babel/helper-skip-transparent-expression-wrappers@^7.12.1":
+  version "7.12.1"
+  resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz#462dc63a7e435ade8468385c63d2b84cce4b3cbf"
+  integrity sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA==
   dependencies:
-    "@babel/helper-member-expression-to-functions" "^7.0.0"
-    "@babel/helper-optimise-call-expression" "^7.0.0"
-    "@babel/traverse" "^7.4.4"
-    "@babel/types" "^7.4.4"
+    "@babel/types" "^7.12.1"
 
-"@babel/helper-simple-access@^7.1.0":
-  version "7.1.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c"
-  integrity sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==
+"@babel/helper-split-export-declaration@^7.12.13":
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz#e9430be00baf3e88b0e13e6f9d4eaf2136372b05"
+  integrity sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==
   dependencies:
-    "@babel/template" "^7.1.0"
-    "@babel/types" "^7.0.0"
+    "@babel/types" "^7.12.13"
 
-"@babel/helper-split-export-declaration@^7.4.4":
-  version "7.4.4"
-  resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677"
-  integrity sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==
-  dependencies:
-    "@babel/types" "^7.4.4"
+"@babel/helper-validator-identifier@^7.12.11":
+  version "7.12.11"
+  resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz"
+  integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==
 
-"@babel/helper-wrap-function@^7.1.0":
-  version "7.2.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz#c4e0012445769e2815b55296ead43a958549f6fa"
-  integrity sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ==
-  dependencies:
-    "@babel/helper-function-name" "^7.1.0"
-    "@babel/template" "^7.1.0"
-    "@babel/traverse" "^7.1.0"
-    "@babel/types" "^7.2.0"
+"@babel/helper-validator-option@^7.12.17":
+  version "7.12.17"
+  resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz#d1fbf012e1a79b7eebbfdc6d270baaf8d9eb9831"
+  integrity sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==
 
-"@babel/helpers@^7.5.4":
-  version "7.5.4"
-  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.5.4.tgz#2f00608aa10d460bde0ccf665d6dcf8477357cf0"
-  integrity sha512-6LJ6xwUEJP51w0sIgKyfvFMJvIb9mWAfohJp0+m6eHJigkFdcH8duZ1sfhn0ltJRzwUIT/yqqhdSfRpCpL7oow==
+"@babel/helper-wrap-function@^7.13.0":
+  version "7.13.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.13.0.tgz#bdb5c66fda8526ec235ab894ad53a1235c79fcc4"
+  integrity sha512-1UX9F7K3BS42fI6qd2A4BjKzgGjToscyZTdp1DjknHLCIvpgne6918io+aL5LXFcER/8QWiwpoY902pVEqgTXA==
   dependencies:
-    "@babel/template" "^7.4.4"
-    "@babel/traverse" "^7.5.0"
-    "@babel/types" "^7.5.0"
+    "@babel/helper-function-name" "^7.12.13"
+    "@babel/template" "^7.12.13"
+    "@babel/traverse" "^7.13.0"
+    "@babel/types" "^7.13.0"
 
-"@babel/highlight@^7.0.0":
-  version "7.5.0"
-  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540"
-  integrity sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==
+"@babel/helpers@^7.13.10":
+  version "7.13.10"
+  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.13.10.tgz#fd8e2ba7488533cdeac45cc158e9ebca5e3c7df8"
+  integrity sha512-4VO883+MWPDUVRF3PhiLBUFHoX/bsLTGFpFK/HqvvfBZz2D57u9XzPVNFVBTc0PW/CWR9BXTOKt8NF4DInUHcQ==
   dependencies:
+    "@babel/template" "^7.12.13"
+    "@babel/traverse" "^7.13.0"
+    "@babel/types" "^7.13.0"
+
+"@babel/highlight@^7.10.4", "@babel/highlight@^7.12.13":
+  version "7.13.10"
+  resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz"
+  integrity sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.12.11"
     chalk "^2.0.0"
-    esutils "^2.0.2"
     js-tokens "^4.0.0"
 
-"@babel/parser@^7.4.4", "@babel/parser@^7.5.0":
-  version "7.5.0"
-  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.5.0.tgz#3e0713dff89ad6ae37faec3b29dcfc5c979770b7"
-  integrity sha512-I5nW8AhGpOXGCCNYGc+p7ExQIBxRFnS2fd/d862bNOKvmoEPjYPcfIjsfdy0ujagYOIYPczKgD9l3FsgTkAzKA==
+"@babel/parser@^7.12.13", "@babel/parser@^7.13.15":
+  version "7.13.15"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.15.tgz#8e66775fb523599acb6a289e12929fa5ab0954d8"
+  integrity sha512-b9COtcAlVEQljy/9fbcMHpG+UIW9ReF+gpaxDHTlZd0c6/UU9ng8zdySAW9sRTzpvcdCHn6bUcbuYUgGzLAWVQ==
 
 "@babel/plugin-external-helpers@^7.0.0":
-  version "7.2.0"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-external-helpers/-/plugin-external-helpers-7.2.0.tgz#7f4cb7dee651cd380d2034847d914288467a6be4"
-  integrity sha512-QFmtcCShFkyAsNtdCM3lJPmRe1iB+vPZymlB4LnDIKEBj2yKQLQKtoxXxJ8ePT5fwMl4QGg303p4mB0UsSI2/g==
+  version "7.12.13"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-external-helpers/-/plugin-external-helpers-7.12.13.tgz#65ef9f4576297250dc601d2aa334769790d9966d"
+  integrity sha512-ClvAsk4RqpE6iacYUjdU9PtvIwC9yAefZENsPfGeG5FckX3jFZLDlWPuyv5gi9/9C2VgwX6H8q1ukBifC0ha+Q==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/helper-plugin-utils" "^7.12.13"
 
 "@babel/plugin-proposal-async-generator-functions@^7.0.0":
-  version "7.2.0"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz#b289b306669dce4ad20b0252889a15768c9d417e"
-  integrity sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ==
+  version "7.13.15"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.13.15.tgz#80e549df273a3b3050431b148c892491df1bcc5b"
+  integrity sha512-VapibkWzFeoa6ubXy/NgV5U2U4MVnUlvnx6wo1XhlsaTrLYWE0UFpDQsVrmn22q5CzeloqJ8gEMHSKxuee6ZdA==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.0.0"
-    "@babel/helper-remap-async-to-generator" "^7.1.0"
-    "@babel/plugin-syntax-async-generators" "^7.2.0"
+    "@babel/helper-plugin-utils" "^7.13.0"
+    "@babel/helper-remap-async-to-generator" "^7.13.0"
+    "@babel/plugin-syntax-async-generators" "^7.8.4"
 
 "@babel/plugin-proposal-object-rest-spread@^7.0.0":
-  version "7.5.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.5.4.tgz#250de35d867ce8260a31b1fdac6c4fc1baa99331"
-  integrity sha512-KCx0z3y7y8ipZUMAEEJOyNi11lMb/FOPUjjB113tfowgw0c16EGYos7worCKBcUAh2oG+OBnoUhsnTSoLpV9uA==
+  version "7.13.8"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.13.8.tgz#5d210a4d727d6ce3b18f9de82cc99a3964eed60a"
+  integrity sha512-DhB2EuB1Ih7S3/IRX5AFVgZ16k3EzfRbq97CxAVI1KSYcW+lexV8VZb7G7L8zuPVSdQMRn0kiBpf/Yzu9ZKH0g==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.0.0"
-    "@babel/plugin-syntax-object-rest-spread" "^7.2.0"
+    "@babel/compat-data" "^7.13.8"
+    "@babel/helper-compilation-targets" "^7.13.8"
+    "@babel/helper-plugin-utils" "^7.13.0"
+    "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
+    "@babel/plugin-transform-parameters" "^7.13.0"
 
-"@babel/plugin-syntax-async-generators@^7.0.0", "@babel/plugin-syntax-async-generators@^7.2.0":
-  version "7.2.0"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz#69e1f0db34c6f5a0cf7e2b3323bf159a76c8cb7f"
-  integrity sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg==
+"@babel/plugin-syntax-async-generators@^7.0.0", "@babel/plugin-syntax-async-generators@^7.8.4":
+  version "7.8.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
+  integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/helper-plugin-utils" "^7.8.0"
 
 "@babel/plugin-syntax-dynamic-import@^7.0.0":
-  version "7.2.0"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.2.0.tgz#69c159ffaf4998122161ad8ebc5e6d1f55df8612"
-  integrity sha512-mVxuJ0YroI/h/tbFTPGZR8cv6ai+STMKNBq0f8hFxsxWjl94qqhsb+wXbpNMDPU3cfR1TIsVFzU3nXyZMqyK4w==
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3"
+  integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/helper-plugin-utils" "^7.8.0"
 
 "@babel/plugin-syntax-import-meta@^7.0.0":
-  version "7.2.0"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.2.0.tgz#2333ef4b875553a3bcd1e93f8ebc09f5b9213a40"
-  integrity sha512-Hq6kFSZD7+PHkmBN8bCpHR6J8QEoCuEV/B38AIQscYjgMZkGlXB7cHNFzP5jR4RCh5545yP1ujHdmO7hAgKtBA==
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51"
+  integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/helper-plugin-utils" "^7.10.4"
 
-"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.2.0":
-  version "7.2.0"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz#3b7a3e733510c57e820b9142a6579ac8b0dfad2e"
-  integrity sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==
+"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871"
+  integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/helper-plugin-utils" "^7.8.0"
 
 "@babel/plugin-transform-arrow-functions@^7.0.0":
-  version "7.2.0"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz#9aeafbe4d6ffc6563bf8f8372091628f00779550"
-  integrity sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg==
+  version "7.13.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.13.0.tgz#10a59bebad52d637a027afa692e8d5ceff5e3dae"
+  integrity sha512-96lgJagobeVmazXFaDrbmCLQxBysKu7U6Do3