protected void genRecipe(MOB mob, final Recipe E, int showNumber, int showFlag)
	throws IOException
	{
		if((showFlag>0)&&(showFlag!=showNumber))
			return;
		StringBuilder str=new StringBuilder(showNumber+". Recipe Data: "+E.getCommonSkillID()+" ("+E.getTotalRecipePages()+"): ");
		for(final String line : E.getRecipeCodeLines())
		{
			final int x=line.indexOf('\t');
			final int len=line.length()>10?10:line.length();
			str.append(line.substring(0,(x<0)?len:x)).append(' ');
		}
		mob.tell(str.toString());
		final Session S=mob.session();
		if((S==null)||((showFlag!=showNumber)&&(showFlag>-999)))
			return;
		while(!S.isStopped())
		{
			final String newName=S.prompt(L("Enter new skill id (?)\n\r:"),"");
			if(newName.equalsIgnoreCase("?"))
			{
				str=new StringBuilder("");
				Ability A=null;
				for(final Enumeration<Ability> e=CMClass.abilities();e.hasMoreElements();)
				{
					A=e.nextElement();
					if(((A.classificationCode()&Ability.ALL_ACODES)==Ability.ACODE_COMMON_SKILL)
					&&((A.classificationCode()&Ability.ALL_DOMAINS)==Ability.DOMAIN_CRAFTINGSKILL))
						str.append(A.ID()+"\n\r");
				}
				mob.tell(L("\n\rCommon Skills:\n\r@x1\n\r",str.toString()));
			}
			else
			if((newName.length()>0)
			&&(CMClass.getAbility(newName)!=null)
			&&((CMClass.getAbility(newName).classificationCode()&Ability.ALL_ACODES)==Ability.ACODE_COMMON_SKILL))
			{
				E.setCommonSkillID(CMClass.getAbility(newName).ID());
				break;
			}
			else
			if(newName.length()>0)
				mob.tell(L("'@x1' is not a valid common skill.  Try ?.",newName));
			else
			{
				mob.tell(L("(no change)"));
				break;
			}
		}
		final String newCount=mob.session().prompt(L("Enter new maximum recipe count (@x1):",""+E.getTotalRecipePages()),"");
		if((newCount.length()>0)&&(CMath.s_int(newCount)>0))
			E.setTotalRecipePages(CMath.s_int(newCount));
		else
			mob.tell(L("(no change)"));
		final Ability A=CMClass.getAbility(E.getCommonSkillID());
		final CraftorAbility C;
		if((A!=null)&&(A.classificationCode()==(Ability.ACODE_COMMON_SKILL|Ability.DOMAIN_CRAFTINGSKILL))&&(A instanceof CraftorAbility))
		{
			C=(CraftorAbility)A;
			mob.tell(L("Params: @x1",CMStrings.replaceAll(C.parametersFormat(), "\t", ",")));
		}
		else
			C = null;
		while(!S.isStopped())
		{
			final String[] recipes = E.getRecipeCodeLines();
			str=new StringBuilder("");
			for(int i=1;i<=recipes.length;i++)
				str.append(i+") "+CMStrings.replaceAll(recipes[i-1],"\t",",")).append("\n");
			if(recipes.length<E.getTotalRecipePages())
				str.append(L("(@x1) ADD NEW RECIPE",""+(recipes.length+1))).append("\n");
			mob.tell(str.toString());
			final String newName=mob.session().prompt(L("Enter a number to add/edit/remove\n\r:"),"");
			final int x=CMath.s_int(newName);
			if((x<=0)||(x>E.getTotalRecipePages()))
				break;
			final List<String> recipeList = new XVector<String>(recipes);
			class Checker 
			{ 
				public String getErrors(String line)
				{
					if(C==null)
						return L("Skill @x1 is not a crafting skill!",E.getCommonSkillID());
					try
					{
						CMLib.ableParms().testRecipeParsing(new StringBuffer(CMStrings.replaceAll(line,",","\t")), C.parametersFormat());
					}
					catch(final CMException cme)
					{
						return cme.getMessage();
					}
					return null;
				} 
			}
			if(x<=recipes.length)
			{
				final String newLine=mob.session().prompt(L("Re-Enter this line, or NULL to delete (?).\n\r:"),"");
				if(newLine.equalsIgnoreCase("?"))
					mob.tell((C==null)?"?":CMStrings.replaceAll(C.parametersFormat(), "\t", ","));
				else
				if(newLine.equalsIgnoreCase("null"))
					recipeList.remove(x-1);
				else
				if(newLine.length()==0)
					mob.tell(L("(No change)"));
				else
				{
					final String errors = new Checker().getErrors(newLine);
					if((errors==null)||(errors.length()==0))
						recipeList.set(x-1, CMStrings.replaceAll(newLine,",","\t"));
					else
						mob.tell(L("Error: @x1, aborting change.",errors));
				}
			}
			else
			{
				final String newLine=mob.session().prompt(L("Enter a new line, or enter to cancel (?).\n\r:"),"");
				if((newLine!=null)&&(newLine.trim().length()>0))
				{
					if(newLine.equalsIgnoreCase("?"))
						mob.tell((C==null)?"?":CMStrings.replaceAll(C.parametersFormat(), "\t", ","));
					else
					{
						final String errors = new Checker().getErrors(newLine);
						if((errors==null)||(errors.length()==0))
							recipeList.add(CMStrings.replaceAll(newLine,",","\t"));
						else
							mob.tell(L("Error: @x1, aborting change.",errors));
					}
				}
				else
					mob.tell(L("(No change)"));
			}
			E.setRecipeCodeLines(recipeList.toArray(new String[0]));
		}
	}