void TNmObjBs::FilterCandToNmObjIdV(
 const TStrV& CandWordStrV, TIntV& NmObjIdV, const bool& DumpP){
  // prepare candidate traversal
  TVec<TStrV> NmObjIdWordStrVV;
  int CandWordStrN=0; int CandWordStrs=CandWordStrV.Len();
  while (CandWordStrN<CandWordStrs){
    // get candidate
    TStr WordStr=CandWordStrV[CandWordStrN];
    //printf("%s ", WordStr.CStr());
    // simple filters
    if (WordStr.Len()<=1){CandWordStrN++; continue;}
    if (WordStr==ParagraphTagStr){CandWordStrN++; continue;}
    if (WordStr==BreakTagStr){CandWordStrN++; continue;}
    if (WordStr==EofTagStr){CandWordStrN++; break;}
    if (IsNumStr(WordStr)){CandWordStrN++; continue;}
    TStr UcWordStr=ChDef->GetUcStr(WordStr);
    //if (SwSet->IsIn(UcWordStr, true)){
    //  CandWordStrN++; continue;}
    if ((WordStr==UcWordStr)&&((WordStr.Len()>4)&&(!IsNmObjAttr(WordStr, noaAcronym)))){
      CandWordStrN++; continue;}
    // unperiod
    if (IsNmObjAttr(WordStr, noaUnperiod)&&(CandWordStrV[CandWordStrN+1]==PeriodTagStr)){
      CandWordStrN+=1;
    }
    // period
    if (WordStr==PeriodTagStr){
      CandWordStrN++; WordStr=CandWordStrV[CandWordStrN];
      if (IsTagStr(WordStr)){continue;}
      if (IsNmObjAttr(WordStr, noaDefined)){
        continue;
      } else 
      if ((CandWordStrN>1)&&(IsNmObjAttr(CandWordStrV[CandWordStrN-2], noaUnperiod))){
        continue;
      } else {
        TStr NextWordStr=CandWordStrV[CandWordStrN+1];
        if (IsFirstCapWordStr(NextWordStr)||IsNmObjAttr(NextWordStr, noaAsCapitalized)){
          continue;
        } else 
        if (!IsNmObj(WordStr)){
          CandWordStrN++; continue;
        }
      }
    }
//    if (WordStr=="British"){
//      printf("");}
    // ignore
    if (IsNmObjAttr(WordStr, noaIgnore)){
      CandWordStrN++; continue;
    } 
    // collect named-object words
    TStrV WordStrV;
    forever {
      WordStrV.Add(WordStr);
      CandWordStrN++; WordStr=CandWordStrV[CandWordStrN];
      if (IsTagStr(WordStr)){break;}
      if (WordStr.Len()<=1){break;}
      if (IsNmObjAttr(WordStr, noaIgnore)){CandWordStrN++; break;}
      if (IsNmObjAttr(WordStr, noaStandalone)){break;}
      if (IsNmObjAttr(WordStrV, noaStandalone)){break;}
    }
    // get normalized version of named-object
    TStrV NrWordStrV; GetNrNmObjStrV(WordStrV, NrWordStrV);
    // simple filters
    if (IsNmObjAttr(NrWordStrV, noaIgnore)){continue;}
    if (IsNmObjAttr(NrWordStrV, noaFirstName)){continue;}
    if (NrWordStrV.Len()>5){
      while (NrWordStrV.Len()>2){NrWordStrV.Del(0);}}
    if (NrWordStrV.Len()==1){
      TStr UcWordStr=ChDef->GetUcStr(NrWordStrV[0]);
      if (SwSet->IsIn(UcWordStr, true)){continue;}
    }
    // add named object
    NmObjIdWordStrVV.Add(NrWordStrV);
  }
  // merge similar words
  for (int NmObjN=0; NmObjN<NmObjIdWordStrVV.Len(); NmObjN++){
    TStrV& WordStrV=NmObjIdWordStrVV[NmObjN];
    if (WordStrV.Len()==1){
      // merge single words
      for (int SubNmObjN=0; SubNmObjN<NmObjIdWordStrVV.Len(); SubNmObjN++){
        TStrV& SubWordStrV=NmObjIdWordStrVV[SubNmObjN];
        if (SubWordStrV.Len()==1){
          if (WordStrV[0]!=SubWordStrV[0]){
            if (IsMatchPfx(WordStrV[0], SubWordStrV[0], 3, 4)){
              // normalize to shorter string
              if (WordStrV[0].Len()<SubWordStrV[0].Len()){SubWordStrV=WordStrV;}
              else {WordStrV=SubWordStrV;}
            }
          }
        }
      }
    } else
    if (WordStrV.Len()>=2){
      TStr LastNm=WordStrV.Last();
      for (int SubNmObjN=0; SubNmObjN<NmObjIdWordStrVV.Len(); SubNmObjN++){
        TStrV& SubWordStrV=NmObjIdWordStrVV[SubNmObjN];
        if (SubWordStrV.Len()==1){
          // merge last-name with [first-name,last-name] pairs
          TStr SubLastNm=SubWordStrV[0];
          if (LastNm!=SubLastNm){
            if (IsMatchPfx(LastNm, SubLastNm, 3, 4)){
              if (LastNm.Len()<SubLastNm.Len()){SubWordStrV=WordStrV;} 
              else {WordStrV=SubWordStrV;}
            }
          }
        } else
        if (false&&(SubWordStrV.Len()==2)){
          // merge [first-name,last-name] with [first-name,last-name] pairs
          if ((WordStrV[0]!=SubWordStrV[0])||(WordStrV[1]!=SubWordStrV[1])){
            if ((IsMatchPfx(WordStrV[0], SubWordStrV[0], 3, 4))&&
             (IsMatchPfx(WordStrV[1], SubWordStrV[1], 3, 4))){
              // normalize to shorter string (first word)
              if (WordStrV[0].Len()<SubWordStrV[0].Len()){
                SubWordStrV[0]=WordStrV[0];}
              else {WordStrV[0]=SubWordStrV[0];}
              // normalize to shorter string (second word)
              if (WordStrV[1].Len()<SubWordStrV[1].Len()){
                SubWordStrV[1]=WordStrV[1];}
              else {WordStrV[1]=SubWordStrV[1];}
            }
          }
        }
      }
    }
  }
  // get named-objects-ids
  NmObjIdV.Gen(NmObjIdWordStrVV.Len(), 0);
  {for (int NmObjN=0; NmObjN<NmObjIdWordStrVV.Len(); NmObjN++){
    TStrV& NmObjWordStrV=NmObjIdWordStrVV[NmObjN];
    int NmObjId=GetNmObjId(NmObjWordStrV, true);
    NmObjIdV.Add(NmObjId);
  }}
  // dump
  if (DumpP){
    printf("Named-Objects: ");
    for (int NmObjN=0; NmObjN<NmObjIdV.Len(); NmObjN++){
      int NmObjId=NmObjIdV[NmObjN];
      TStr NmObjStr=GetNmObjStr(NmObjId);
      printf("%s ", NmObjStr.CStr());
    }
    printf("\n");
  }
}
int
main (void)
{
	int record_counter = 0;//It stores how many records there are

	/*PAMNIP was defined at Manip.h
	ManipInitialize () was declared at Manip.h and was implemented at Manip.c, 
	and its function is to make all needed function well prepared
	Note the function called malloc () and its return value points to the allocated memory*/
	PMANIP wangluo2 = ManipInitialize ();

	/*PSTUDENT was defined at Student.h
	Construct () was declared at Manip.h and realized at Manip.c, 
	and it creates the first node whose members pi and pg was not allocated any memory
	But note phead points to a memory allocated by malloc()*/
	PSTUDENT phead = wangluo2->Construct ();

	while (1)//This is the main loop
	{
		int choice;

		/*ShowFace () was declared at MainFace.h and was defined at MainFace.c
		It shows the main menu*/
		ShowFace ();

		//Hints about the total records
		printf ("      THERE ARE NOW %d RECORD(S) ALTOGETHER.\n\n", record_counter);

		printf ("      ENTER A FUNCTION NUMBER( 1 ~ 9): ");
		scanf ("%d", &choice);

		if (choice > 9 || choice < 1)
			/*ShowError () and IN_ERR was declared at MainFace.h, and the former was defined at MainFace.c,
			and it shows different error information according to the input*/
			ShowError (IN_ERR);
		else
		{
			switch (choice)//Handle users legal inputs
			{
				case ADD: //ADD was defined at MainFace.h functioning as an enum constant
					{
						/*Add () was declared at Manip.h and realized at Manip.c
						It adds a student record to the end of the existing list
						ReadInfo () and ReadGrade () was declared and implemented @ respectively Student.h and Student.c*/
						PINFO pi_tmp = ReadInfo (phead);
						if (pi_tmp == NULL)//This means ReadInfo () encoutered illegal inputs
							break;
						wangluo2->Add (phead, pi_tmp, ReadGrade ());
						
						record_counter++;//Added one record

						save_flag = 1;

						printf ("\n      ADDITION FINISHED.\n");//6 blanks
						Enter2Retn ();//@ MainFace.h and MainFace.c
					}
					break;

				case LOAD:
					{
						int tmp;//Stores LoadFromFile ()'s return value, which could tell me whether to use getchar ()
						if (tmp = wangluo2->LoadFromFile (phead, &record_counter))//Either 1 or 2; It is =, not ==
						{
							save_flag = 1;
							printf ("\n      LOADING FINISHED.\n");
							if (tmp == 1)//1 means loading source has no repeated record
							{
								Enter2Retn ();
							}
							else
								if (tmp == 2)//2 means loading source has repeated record
								{
									Enter2Retn1 ();
								}
						}
						else//Neither 1 nor 2 means returned 0, it was handled by the function itself; so the outer did nothing
							break;
					}
					break;

				case DEL: //DEL was defined at MainFace.h functioning as an enum constant
					{
						char in[32];
						PSTUDENT ps_before;
						if (phead->pnext == NULL)
						{
							ShowError (NO_RECORD);
							break;
						}
						printf ("\n      ENTER THE NUMBER OR NAME: ");
						getchar ();//Absorbs character
						gets (in);
						if (IsNumStr (in))
							/*InquireBefore () searches the list for the student just before the inputted position
							It was declared at Manip.h and realized at Manip.c
							SEARCH_NUM was defined @ Manip.h and works as a flag of search mode, that is number based or name based*/
							ps_before = wangluo2->InquireBefore (phead, SEARCH_NUM, in);
						else
							ps_before = wangluo2->InquireBefore (phead, SEARCH_NAME, in);//SEARCH_NAME means search a student by name
						if (ps_before == NULL)
							ShowError (UNFOUND);//UNFOND was defined @ MainFace.h
						else
						{
							int tmp;
							printf ("\n      ARE YOU GOING TO DELETE THE RECORD: %s\n      1 FOR DELETE AND 0 FOR NOT.\n      (1 / 0): ", in);
							scanf ("%d", &tmp);
							if (tmp == 1)
							{
								/*DestroyPs ()'s declaration and definition were respectively @ Student.h and Student.c
								The function calls free () to release the dynamically allocated memory at a STUDENT struct*/ 
								ps_before->pnext->DestroyPs (ps_before);

								record_counter--;

								save_flag = 1;
								printf ("\n      DELETION COMPETED.\n");
								Enter2Retn ();
							}
							else
							{
								if (tmp == 0)
								{
									printf ("\n      DELETION CANCELLED.\n");
									Enter2Retn1 ();
									getchar ();
								}
								else
									ShowError (IN_ERR);
							}
						}
					}
					break;

				case TO_FILE: //TO_FILE was defined at MainFace.h functioning as an enum constant
					{
						if (phead->pnext == NULL)
						{
							ShowError (NO_RECORD);
							break;
						}
						wangluo2->SaveToFile (phead);
						save_flag = 0;
						printf ("\n      SAVE COMPLETED.\n");
						Enter2Retn ();
					}
					break;

				case SORT: //SORT was defined at MainFace.h functioning as an enum constant
					{
						int sort_type;
						if (phead->pnext == NULL)
						{
							ShowError (NO_RECORD);
							break;
						}
						//printf ("\n      UNSUPPORTED NOW!\n");
						ShowSubMenu (MENU_SORT);
						scanf ("%d", &sort_type);
						if (sort_type <1 || sort_type > 5)
						{
							ShowError (IN_ERR);
							break;
						}
						wangluo2->SSort (phead, sort_type);
						printf ("\n      SORT FINISHED.\n");
						save_flag = 1;
						Enter2Retn ();
					}
					break;

				case INQUIRE: //INQUIRE was defined at MainFace.h functioning as an enum constant
					{
						char in[32];
						PSTUDENT ps_tmp;
						if (phead->pnext == NULL)
						{
							ShowError (NO_RECORD);
							break;
						}
						printf ("\n      ENTER THE NUMBER OR NAME: ");
						getchar ();
						gets (in);
						if (IsNumStr (in))
							/*Inquire () searchs the designated record
							It was declared and defined respectively @ Manip.h and @ Manip.c*/
							ps_tmp = wangluo2->Inquire (phead, SEARCH_NUM, in);
						else
							ps_tmp = wangluo2->Inquire (phead, SEARCH_NAME, in);
						if (ps_tmp == NULL)
							ShowError (UNFOUND);
						else
						{
							/*Display () was declared and defined respectively @ Manip.h and @ Manip.c
							It shows all the record at one time
							It may not be good if there are too many records*/
							ps_tmp->DisplayInfoPs (ps_tmp);
							ps_tmp->DisplayGradePs (ps_tmp);
							Enter2Retn1 ();
						}
					}
					break;

				case MOD: //MOD was defined at MainFace.h functioning as an enum constant
					{
						int mod_type;
						char in[32];
						PSTUDENT ps_tmp;
						if (phead->pnext == NULL)
						{
							ShowError (NO_RECORD);
							break;
						}
						ShowSubMenu (MENU_MOD);
						scanf ("%d", &mod_type);
						if (mod_type == MOD_INFO || mod_type == MOD_GRADE)
							;
						else
						{
							ShowError (IN_ERR);
							break;
						}
						printf ("\n      ENTER THE NUMBER OR NAME: ");
						getchar ();
						gets (in);
						if (IsNumStr (in))
							/*Inquire () searchs the designated record
							It was declared and defined respectively @ Manip.h and @ Manip.c*/
							ps_tmp = wangluo2->Inquire (phead, SEARCH_NUM, in);
						else
							ps_tmp = wangluo2->Inquire (phead, SEARCH_NAME, in);
						if (ps_tmp == NULL)
							ShowError (UNFOUND);
						else
						{
							if (mod_type == MOD_INFO)
								ModifyInfo(ps_tmp, phead);
							else
								ps_tmp->ModifyGrade(ps_tmp);
						}
						save_flag = 1;
					}
					break;

				case DISP: //DISP was defined at MainFace.h functioning as an enum constant
					{
						/*DisplayGrade () was declared and defined respectively @ Manip.h and @ Manip.c
						It shows the GRADE struct of the appointed STUDENT struct*/
						int disp_type;
						if (phead->pnext == NULL)
						{
							ShowError (NO_RECORD);
							break;
						}
						ShowSubMenu (MENU_DISP);
						scanf ("%d", &disp_type);
						switch (disp_type)
						{
							case DISP_GRADE:
								{
									wangluo2->DisplayGrade (phead);
									Enter2Retn ();
								}
								break;
							case DISP_INFO:
								{
									wangluo2->DisplayInfo (phead);
									Enter2Retn ();
								}
								break;
							case DISP_ANALYZE:
								{
									wangluo2->AnalyzeGrade (phead);
									Enter2Retn ();
								}
								break;
							default: ShowError (IN_ERR); break;
						}
					}
					break;

				case QUIT: //QUIT was defined at MainFace.h functioning as an enum constant
					{
						char quit_flag;

						if (save_flag == 1)
							printf ("\n      THERE ARE SOME MODIFICATIONS MADE!\n");

						printf ("\n      YOU ARE GOING TO QUIT? (Y / N): ");
						getchar ();//Absorbs character @ buffer
						scanf ("%c", &quit_flag);
						if (quit_flag == 'Y' || quit_flag == 'y')
						{
							/*Destroy () was declared and defined respectively @ Manip.h and @ Manip.c
							It free the runtime allocated memory of INFO &GRADE for all the records in the list*/
							wangluo2->Destroy (phead);
							free (phead);
							free (wangluo2);

							printf ("\n      PRESS ENTER TO QUIT....");
							getchar ();
							getchar ();
							exit (EXIT_SUCCESS);
						}
						else
						{
							if (quit_flag == 'N' || quit_flag == 'n')
							{
								printf ("\n      QUIT CANCELLED.\n");
								Enter2Retn ();
							}
							else
								ShowError (IN_ERR);
						}
					 }
					break;

			}
		}
	}
	return EXIT_SUCCESS;
}