private <E> Feature feature(
            Class<E> clazz, Pair<Mention, ClusteredMention> input, Option<Double> count) {

          // --Variables
          Mention onPrix =
              input.getFirst(); // the first mention (referred to as m_i in the handout)
          Mention candidate =
              input.getSecond().mention; // the second mention (referred to as m_j in the handout)
          Entity candidateCluster =
              input.getSecond().entity; // the cluster containing the second mention

          // --Features:w
          if (clazz.equals(Feature.ExactMatch.class)) {
            // (exact string match)
            return new Feature.ExactMatch(onPrix.gloss().equals(candidate.gloss()));
          } else if (clazz.equals(Feature.SentenceDist.class)) {
            return new Feature.SentenceDist(
                Math.abs(
                    onPrix.doc.indexOfMention(onPrix) - candidate.doc.indexOfMention(candidate)));
          } else if (clazz.equals(Feature.MentionDist.class)) {
            return new Feature.MentionDist(
                Math.abs(
                    onPrix.doc.indexOfSentence(onPrix.sentence)
                        - candidate.doc.indexOfSentence(candidate.sentence)));
          } else if (clazz.equals(Feature.EitherHeadWordPronoun.class)) {
            return new Feature.EitherHeadWordPronoun(
                Pronoun.isSomePronoun(onPrix.gloss()) || Pronoun.isSomePronoun(candidate.gloss()));
          } else if (clazz.equals(Feature.CandidateNERTag.class)) {
            return new Feature.CandidateNERTag(candidate.headToken().nerTag());
          } else if (clazz.equals(Feature.CandidateSpeaker.class)) {
            return new Feature.CandidateSpeaker(candidate.headToken().speaker());
          } else if (clazz.equals(Feature.FixedSpeaker.class)) {
            return new Feature.FixedSpeaker(onPrix.headToken().speaker());
          } else if (clazz.equals(Feature.HeadWordMatch.class)) {
            return new Feature.HeadWordMatch(onPrix.equals(candidate.headWord()));
          } else if (clazz.equals(Feature.HeadWordLemmaMatch.class)) {
            return new Feature.HeadWordLemmaMatch(
                onPrix.headToken().lemma().equals(candidate.headToken().lemma()));
          } else if (clazz.equals(Feature.FixedNERTag.class)) {
            return new Feature.FixedNERTag(onPrix.headToken().nerTag());
          } else if (clazz.equals(Feature.SpeakerMatch.class)) {
            return new Feature.SpeakerMatch(
                candidate.headToken().speaker().equals(onPrix.headToken().speaker()));
          } else if (clazz.equals(Feature.NERTagMatch.class)) {
            return new Feature.NERTagMatch(
                candidate.headToken().nerTag().equals(onPrix.headToken().nerTag()));
          } else if (clazz.equals(Feature.CandidatePOSTag.class)) {
            return new Feature.CandidatePOSTag(candidate.headToken().posTag());
          } else if (clazz.equals(Feature.FixedPOSTag.class)) {
            return new Feature.FixedPOSTag(onPrix.headToken().posTag());
          } else if (clazz.equals(Feature.GenderMatch.class)) {
            Pair<Boolean, Boolean> match = Util.haveGenderAndAreSameGender(onPrix, candidate);
            boolean finalMatch = (!match.getFirst() || match.getSecond());
            return new Feature.GenderMatch(finalMatch);
          } else if (clazz.equals(Feature.NumberMatch.class)) {
            Pair<Boolean, Boolean> match = Util.haveNumberAndAreSameNumber(onPrix, candidate);
            boolean finalMatch = (!match.getFirst() || match.getSecond());
            return new Feature.NumberMatch(finalMatch);
          }
          //			} else if(clazz.equals(Feature.NewFeature.class) {
          /*
           * TODO: Add features to return for specific classes. Implement calculating values of features here.
           */

          else {
            throw new IllegalArgumentException("Unregistered feature: " + clazz);
          }
        }