public static boolean analysisNSMXMJ(AnalysisOutput o, List<AnalysisOutput> candidates)
      throws MorphException {

    int idxVbSfix = VerbUtil.endsWithVerbSuffix(o.getStem());
    if (idxVbSfix == -1) return false;

    o.setVsfx(o.getStem().substring(idxVbSfix));
    o.setStem(o.getStem().substring(0, idxVbSfix));
    o.setPatn(PatternConstants.PTN_NSMXMJ);
    o.setPos(PatternConstants.POS_NOUN);

    WordEntry entry = DictionaryUtil.getWordExceptVerb(o.getStem());

    if (entry != null) {
      if (entry.getFeature(WordEntry.IDX_NOUN) == '0') return false;
      else if (o.getVsfx().equals("하") && entry.getFeature(WordEntry.IDX_DOV) != '1') return false;
      else if (o.getVsfx().equals("되") && entry.getFeature(WordEntry.IDX_BEV) != '1') return false;
      else if (o.getVsfx().equals("내") && entry.getFeature(WordEntry.IDX_NE) != '1') return false;
      o.setScore(AnalysisOutput.SCORE_CORRECT); // '입니다'인 경우 인명 등 미등록어가 많이 발생되므로 분석성공으로 가정한다.
    } else {
      o.setScore(AnalysisOutput.SCORE_ANALYSIS); // '입니다'인 경우 인명 등 미등록어가 많이 발생되므로 분석성공으로 가정한다.
    }

    candidates.add(o);

    return true;
  }
  /**
   * 어간부가 음/기 로 끝나는 경우
   *
   * @param o the analyzed output
   * @param candidates candidates
   * @throws MorphException throw exception
   */
  public static boolean analysisMJ(AnalysisOutput o, List<AnalysisOutput> candidates)
      throws MorphException {

    int strlen = o.getStem().length();

    if (strlen < 2) return false;

    char[] chrs = MorphUtil.decompose(o.getStem().charAt(strlen - 1));
    boolean success = false;

    if (o.getStem().charAt(strlen - 1) != '기' && !(chrs.length == 3 && chrs[2] == 'ㅁ'))
      return false;

    String start = o.getStem();
    String end = "";
    if (o.getStem().charAt(strlen - 1) == '기') {
      start = o.getStem().substring(0, strlen - 1);
      end = "기";
    } else if (o.getStem().charAt(strlen - 1) == '음') {
      start = o.getStem().substring(0, strlen - 1);
      end = "음";
    }

    String[] eomis = EomiUtil.splitEomi(start, end);
    if (eomis[0] == null) return false;
    String[] pomis = EomiUtil.splitPomi(eomis[0]);
    o.setStem(pomis[0]);
    o.addElist(eomis[1]);
    o.setPomi(pomis[1]);

    try {
      if (analysisVMJ(o.clone(), candidates)) return true;
      if (analysisNSMJ(o.clone(), candidates)) return true;
      if (analysisVMXMJ(o.clone(), candidates)) return true;
    } catch (CloneNotSupportedException e) {
      throw new MorphException(e.getMessage(), e);
    }

    if (DictionaryUtil.getVerb(o.getStem()) != null) {
      o.setPos(PatternConstants.POS_VERB);
      o.setPatn(PatternConstants.PTN_VMJ);
      o.setScore(AnalysisOutput.SCORE_CORRECT);
      candidates.add(o);
      return true;
    }

    return false;
  }
  /**
   * 용언 + '음/기' + 조사(PTN_VMXMJ)
   *
   * @param o the analyzed output
   * @param candidates candidates
   * @throws MorphException throw exception
   */
  public static boolean analysisVMJ(AnalysisOutput o, List<AnalysisOutput> candidates)
      throws MorphException {

    String[] irrs = IrregularUtil.restoreIrregularVerb(o.getStem(), o.getElist().get(0));
    if (irrs != null) {
      o.setStem(irrs[0]);
      o.setElist(irrs[1], 0);
    }

    if (DictionaryUtil.getVerb(o.getStem()) != null) {
      o.setPatn(PatternConstants.PTN_VMJ);
      o.setPos(PatternConstants.POS_VERB);
      o.setScore(AnalysisOutput.SCORE_CORRECT);
      candidates.add(o);
      return true;
    }

    return false;
  }
  /**
   * 용언 + '아/어' + 보조용언 + '음/기' + 조사(PTN_VMXMJ)
   *
   * @param o the analyzed output
   * @param candidates candidates
   * @throws MorphException throw exception
   */
  public static boolean analysisVMXMJ(AnalysisOutput o, List<AnalysisOutput> candidates)
      throws MorphException {

    int idxXVerb = VerbUtil.endsWithXVerb(o.getStem());

    if (idxXVerb != -1) { // 2. 사랑받아보다
      String eogan = o.getStem().substring(0, idxXVerb);
      o.setXverb(o.getStem().substring(idxXVerb));

      String[] stomis = null;
      if (eogan.endsWith("아") || eogan.endsWith("어"))
        stomis =
            EomiUtil.splitEomi(
                eogan.substring(0, eogan.length() - 1), eogan.substring(eogan.length() - 1));
      else stomis = EomiUtil.splitEomi(eogan, "");
      if (stomis[0] == null) return false;

      String[] irrs = IrregularUtil.restoreIrregularVerb(stomis[0], stomis[1]);
      if (irrs != null) {
        o.setStem(irrs[0]);
        o.addElist(irrs[1]);
      } else {
        o.setStem(stomis[0]);
        o.addElist(stomis[1]);
      }

      if (DictionaryUtil.getVerb(o.getStem()) != null) {
        o.setPatn(PatternConstants.PTN_VMXMJ);
        o.setPos(PatternConstants.POS_VERB);
        o.setScore(AnalysisOutput.SCORE_CORRECT);
        candidates.add(o);
        return true;
      } else if (analysisNSMXMJ(o, candidates)) {
        return true;
      }
    }

    return false;
  }