class LineExpander implements org.languagetool.rules.LineExpander {

  private static final Pattern ESCAPE_REGEX = Pattern.compile("\\\\");

  private static final LoadingCache<String, String[]> verbFormCache = CacheBuilder.newBuilder()
    .expireAfterAccess(10, TimeUnit.MINUTES)
    .build(new CacheLoader<String, String[]>() {
      @Override
      public String[] load(@NotNull String verb) throws IOException {
        return GermanSynthesizer.INSTANCE.synthesizeForPosTags(verb, s -> s.startsWith("VER:"));
      }
    });

  private static List<String> handleLineWithPrefix(String line) {<FILL_FUNCTION_BODY>}

  @Override
  public List<String> expandLine(String line) {
    return isLineWithVerbPrefix(line) ? handleLineWithPrefix(line) :
           isLineWithFlag(line) ? handleLineWithFlags(line) :
           Collections.singletonList(cleanTagsAndEscapeChars(line));
  }

  private boolean isLineWithFlag(String line) {
    int idx = line.indexOf('/');
    return !line.startsWith("#") && idx > 0 && line.charAt(idx-1) != '\\';
  }

  private boolean isLineWithVerbPrefix(String line) {
    int idx = line.indexOf('_');
    return !line.startsWith("#") && idx > 0 && line.charAt(idx-1) != '\\';
  }

  private List<String> handleLineWithFlags(String line) {
    List<String> result = new ArrayList<>();
    String[] parts = cleanTagsAndEscapeChars(line).split("/");
    if (parts.length != 2) {
      throw new IllegalArgumentException("Unexpected line format, expected at most one slash: " + line);
    }
    String word = parts[0];
    String suffix = parts[1];
    for (int i = 0; i < suffix.length(); i++) {
      char c = suffix.charAt(i);
      if (c == 'S') {
        add(result, word);
        result.add(word + "s");
      } else if (c == 'N') {
        add(result, word);
        result.add(word + "n");
      } else if (c == 'E') {
        add(result, word);
        result.add(word + "e");
      } else if (c == 'F') {
        add(result, word);
        result.add(word + "in"); // (m/f)
      } else if (c == 'T') {
        add(result, word);
        if (word.endsWith("straße") || word.endsWith("strasse")) {
          result.add(word.replaceAll("stra(ß|ss)e", "str."));
        } 
        if (word.endsWith("Straße") || word.endsWith("Strasse")) {
          result.add(word.replaceAll("Stra(ß|ss)e", "Str."));
        } 
      } else if (c == 'A' || c == 'P') { // Adjektiv / Partizip
        add(result, word);
        if (word.endsWith("e")) {
          result.add(word + "r");
          result.add(word + "s");
          result.add(word + "n");
          result.add(word + "m");
        } else {
          result.add(word + "e");
          result.add(word + "er");
          result.add(word + "es");
          result.add(word + "en");
          result.add(word + "em");
        }
      } else {
        throw new IllegalArgumentException("Unknown suffix: " + suffix + " in line: " + line);
      }
    }
    return result;
  }

  private void add(List<String> result, String word) {
    if (!result.contains(word)) {
      result.add(word);
    }
  }

  // ignore "#..." so it can be used as a tag:
  private static String cleanTagsAndEscapeChars(String s) {
    int idx = s.indexOf('#');
    if (idx != -1) {
      s = s.substring(0, idx);
    }
    return ESCAPE_REGEX.matcher(s).replaceAll("").trim();
  }
}

    List<String> result = new ArrayList<>();
    String[] parts = cleanTagsAndEscapeChars(line).split("_");
    if (parts.length != 2) {
      throw new IllegalArgumentException("Unexpected line format, expected at most one '_': " + line);
    }
    if (parts[0].contains("/") || parts[1].contains("/")) {
      throw new IllegalArgumentException("Unexpected line format, '_' cannot be combined with '/': " + line);
    }
    if (parts[1].equals("in")) {
      // special case for the common gender gap characters:
      result.add(parts[0] + "_in");
      result.add(parts[0] + "_innen");
      result.add(parts[0] + "*in");
      result.add(parts[0] + "*innen");
      result.add(parts[0] + ":in");
      result.add(parts[0] + ":innen");
      //result.add(parts[0] + "in");   // see if we can comment in these cases, too
      //result.add(parts[0] + "innen");
      //result.add(parts[0] + "e");
      //result.add(parts[0] + "en");
    } else {
      String[] forms = verbFormCache.getUnchecked(parts[1]);
      if (forms.length == 0) {
        throw new RuntimeException("Could not expand '" + parts[1] + "' from line '" + line + "', no forms found");
      }
      Set<String> formSet = new HashSet<>(Arrays.asList(forms));
      for (String form : formSet) {
        if (!form.contains("ß") && form.length() > 0 && Character.isLowerCase(form.charAt(0))) {
          // skip these, it's too risky to introduce old spellings like "gewußt" from the synthesizer
          result.add(parts[0] + form);
        }
      }
      result.add(parts[0] + "zu" + parts[1]);  //  "zu<verb>" is not part of forms from synthesizer
      result.add(StringTools.uppercaseFirstChar(parts[0]) + parts[1] + "s");  //  Genitiv, e.g. "des Weitergehens"
    }
    return result;
  
<no_super_class>