class EnglishSynthesizer extends BaseSynthesizer {

  private static final String RESOURCE_FILENAME = "/en/english_synth.dict";
  private static final String TAGS_FILE_NAME = "/en/english_tags.txt";
  private static final String SOR_FILE_NAME = "/en/en.sor";
  
  private static final List<String> exceptions = Arrays.asList("ne'er", "e'er", "o'er", "ol'", "ma'am", "n't", "informations");

  // A special tag to add determiners.
  private static final String ADD_DETERMINER = "+DT";

  // A special tag to add only indefinite articles.
  private static final String ADD_IND_DETERMINER = "+INDT";

  private final AvsAnRule aVsAnRule = new AvsAnRule(JLanguageTool.getMessageBundle(Languages.getLanguageForShortCode("en")));

  public static final EnglishSynthesizer INSTANCE = new EnglishSynthesizer();

  /** @deprecated use {@link #INSTANCE} */
  public EnglishSynthesizer(Language lang) {
    this();
  }

  private EnglishSynthesizer() {
    super(SOR_FILE_NAME, RESOURCE_FILENAME, TAGS_FILE_NAME, "en");
  }

  /**
   * Get a form of a given AnalyzedToken, where the form is defined by a
   * part-of-speech tag.
   * 
   * @param token AnalyzedToken to be inflected.
   * @param posTag A desired part-of-speech tag.
   * @return String value - inflected word.
   */
  @Override
  public String[] synthesize(AnalyzedToken token, String posTag) throws IOException {
    if (posTag.startsWith(SPELLNUMBER_TAG)) {
      return super.synthesize(token, posTag);
    }
    String aOrAn = aVsAnRule.suggestAorAn(token.getToken());
    if (ADD_DETERMINER.equals(posTag)) {
      return new String[] { aOrAn, "the " + StringTools.lowercaseFirstCharIfCapitalized(token.getToken()) };
    } else if (ADD_IND_DETERMINER.equals(posTag)) {
      return new String[] { aOrAn };
    }
    return removeExceptions(super.synthesize(token, posTag));
  }

  /**
   * Special English regexp based synthesizer that allows adding articles
   * when the regexp-based tag ends with a special signature {@code \\+INDT} or {@code \\+DT}.
   * 
   * @since 2.5
   */
  @Override
  public String[] synthesize(AnalyzedToken token, String posTag, boolean posTagRegExp) throws IOException {
    if (posTag.startsWith(SPELLNUMBER_TAG)) {
      return synthesize(token, posTag);
    }
    if (posTagRegExp) {
      String myPosTag = posTag;
      String det = "";
      if (posTag.endsWith(ADD_IND_DETERMINER)) {
        myPosTag = myPosTag.substring(0, myPosTag.indexOf(ADD_IND_DETERMINER) - "\\".length());
        det = aVsAnRule.suggestAorAn(token.getLemma());
        det = det.substring(0, det.indexOf(' ') + " ".length());
      } else if (posTag.endsWith(ADD_DETERMINER)) {
        myPosTag = myPosTag.substring(0, myPosTag.indexOf(ADD_DETERMINER) - "\\".length());
        det = "the ";
      }

      initPossibleTags();
      Pattern p = Pattern.compile(myPosTag);
      List<String> results = new ArrayList<>();

      for (String tag : possibleTags) {
        Matcher m = p.matcher(tag);
        if (m.matches() && token.getLemma() != null) {
          lookup(token.getLemma(), tag, results, det);
        }
      }
      return removeExceptions(results.toArray(new String[0]));
    }
    return removeExceptions(synthesize(token, posTag));
  }

  private void lookup(String lemma, String posTag, List<String> results, String determiner) {<FILL_FUNCTION_BODY>}
  
  @Override
  protected boolean isException(String w) {
    // remove: 've, 's, 're...
    return w.startsWith("'") || exceptions.contains(w);  
  }



}

    List<String> lookup = super.lookup(lemma, posTag);
    for (String result : lookup) {
      //results.add(determiner + StringTools.lowercaseFirstCharIfCapitalized(result)); //why lowercase?
      results.add(determiner + result);
    }
  
<methods>public void <init>(java.lang.String, java.lang.String, java.lang.String, org.languagetool.Language) ,public void <init>(java.lang.String, java.lang.String, java.lang.String, java.lang.String) ,public void <init>(java.lang.String, java.lang.String, org.languagetool.Language) ,public void <init>(java.lang.String, java.lang.String, java.lang.String) ,public java.lang.String getPosTagCorrection(java.lang.String) ,public java.lang.String getRomanNumber(java.lang.String) ,public java.lang.String getSpelledNumber(java.lang.String) ,public IStemmer getStemmer() ,public java.lang.String getTargetPosTag(List<java.lang.String>, java.lang.String) ,public java.lang.String[] synthesize(org.languagetool.AnalyzedToken, java.lang.String) throws java.io.IOException,public java.lang.String[] synthesize(org.languagetool.AnalyzedToken, java.lang.String, boolean) throws java.io.IOException,public java.lang.String[] synthesizeForPosTags(java.lang.String, Predicate<java.lang.String>) throws java.io.IOException<variables>public final java.lang.String SPELLNUMBER_FEMININE_TAG,public final java.lang.String SPELLNUMBER_ROMAN_TAG,public final java.lang.String SPELLNUMBER_TAG,private volatile Dictionary dictionary,private final non-sealed org.languagetool.synthesis.ManualSynthesizer manualSynthesizer,private final non-sealed org.languagetool.synthesis.Soros numberSpeller,protected volatile List<java.lang.String> possibleTags,private final non-sealed org.languagetool.synthesis.ManualSynthesizer removalSynthesizer,private final non-sealed org.languagetool.synthesis.ManualSynthesizer removalSynthesizer2,private final non-sealed java.lang.String resourceFileName,private final non-sealed org.languagetool.synthesis.Soros romanNumberer,private final non-sealed java.lang.String sorosFileName,private final non-sealed IStemmer stemmer,private final non-sealed java.lang.String tagFileName