@SafeVarargs
  @Contract(pure = true)
  public static @NotNull HtmlChunk template(@NotNull @Nls String template,
                                            Map.Entry<@NotNull @NonNls String, @NotNull HtmlChunk>... substitutions) {
    String[] parts = template.split("\\$", -1);
    if (parts.length % 2 != 1) {
      throw new IllegalArgumentException("Invalid template (must have even number of '$' characters): " + template);
    }
    HtmlBuilder builder = new HtmlBuilder();
    Map<String, HtmlChunk> chunkMap = Stream.of(substitutions).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    for (int i = 0; i < parts.length; i++) {
      String part = parts[i];
      if (i % 2 == 0) {
        builder.append(part);
      }
      else if (part.isEmpty()) {
        builder.append("$");
      }
      else {
        builder.append(Objects.requireNonNull(chunkMap.get(part), part));
      }
    }
    return builder.toFragment();
  }
@SafeVarargs
  @Contract(pure = true)
  public static @NotNull HtmlChunk template(@NotNull @Nls String template,
                                            Map.Entry<@NotNull @NonNls String, @NotNull HtmlChunk>... substitutions)