public Object eval(Object str, Object[] choices, boolean emptyOK) throws CMException
				{ // ability
					if (!(str instanceof String))
						throw new CMException("Bad type: " + ((str == null) ? "null" : str.getClass().getName()));
					final StringBuffer list = new StringBuffer("");
					for (final Enumeration<Ability> e = CMClass.abilities(); e.hasMoreElements();)
						list.append(e.nextElement().ID() + ", ");
					if (((String) str).trim().length() == 0)
					{
						if (emptyOK)
							return "";
						throw new CMException("You must enter an ability ID, choose from the following: " + list.toString());
					}
					Ability A = CMClass.getAbility((String) str);
					if (A == null)
						A = CMClass.findAbility((String) str);
					if ((A.classificationCode() & Ability.ALL_DOMAINS) == Ability.DOMAIN_ARCHON)
						A = null;
					if (A == null)
						throw new CMException("Invalid ability id, choose from the following: " + list.toString());
					return A.ID();
				}
			};
		case $EXISTING_QUEST_NAME:
			return new GenericEditor.CMEval()
			{
				@Override
				public Object eval(Object str, Object[] choices, boolean emptyOK) throws CMException
				{ // existing quest name
					if (!(str instanceof String))
						throw new CMException("Bad type: " + ((str == null) ? "null" : str.getClass().getName()));
					if (((String) str).trim().length() == 0)
					{
						if (emptyOK)
							return "";
						throw new CMException("You must enter a quest name!");
					}
					final Quest Q = CMLib.quests().fetchQuest(((String) str).trim());
					if (Q == null)
						throw new CMException("A quest of the name '" + ((String) str).trim() + "' does not exist.  Enter another.");
					return Q.name();
				}
			};
		case $HIDDEN:
			return new GenericEditor.CMEval()
			{
				@Override
				public Object eval(Object str, Object[] choices, boolean emptyOK) throws CMException
				{ // hidden
					return str;
				}
			};
		case $FACTION:
			return new GenericEditor.CMEval()
			{
				@Override
				public Object eval(Object str, Object[] choices, boolean emptyOK) throws CMException
				{ // faction
					if (!(str instanceof String))
						throw new CMException("Bad type: " + ((str == null) ? "null" : str.getClass().getName()));
					if (((String) str).trim().length() == 0)
					{
						if (emptyOK)
							return "";
						throw new CMException("You must enter a faction id!");
					}
					final Faction F = CMLib.factions().getFaction((String) str);
					if (F == null)
						throw new CMException("A faction of the name '" + ((String) str).trim() + "' does not exist.  Enter another.");
					return F.factionID();
				}
			};
		case $TIMEEXPRESSION:
			return new GenericEditor.CMEval()
			{
				@Override
				public Object eval(Object str, Object[] choices, boolean emptyOK) throws CMException
				{ // timeexpression
					if (!(str instanceof String))
						throw new CMException("Bad type: " + ((str == null) ? "null" : str.getClass().getName()));
					if (((String) str).trim().length() == 0)
					{
						if (emptyOK)
							return "";
						throw new CMException("You must enter an expression!");
					}
					if (!CMLib.time().isTickExpression((String) str))
						throw new CMException("Invalid time mathematical expression.  Use numbers,+,-,*,/,(), and ? only.  You may add ticks, minutes, hours, days, mudhours, muddays, mudweeks, mudmonths, mudyears.");
					return str;
				}