public Object eval(Object str, Object[] choices, boolean emptyOK) throws CMException
				{ // 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!");
					}
					for (int i = 0; i < ((String) str).length(); i++)
					{
						if ((!Character.isLetterOrDigit(((String) str).charAt(i))) && (((String) str).charAt(i) != '_'))
							throw new CMException("Quest names may only contain letters, digits, or _ -- no spaces or special characters.");
					}

					if (CMLib.quests().fetchQuest(((String) str).trim()) != null)
						throw new CMException("A quest of that name already exists.  Enter another.");
					return ((String) str).trim();
				}
			};
		case $CHOOSE:
			return new GenericEditor.CMEval()
			{
				@Override
				public Object eval(Object str, Object[] choices, boolean emptyOK) throws CMException
				{ // choose
					if ((choices == null) || (choices.length == 0))
						throw new CMException("NO choices?!");
					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 value!");
					}
					final int x = CMParms.indexOf(choices, ((String) str).toUpperCase().trim());
					if (x < 0)
						throw new CMException("That is not a valid option.  Choices include: " + CMParms.toListString(choices));
					return choices[x];
				}
			};
		case $ITEMXML:
			return new GenericEditor.CMEval()
			{
				@Override
				public Object eval(Object str, Object[] choices, boolean emptyOK) throws CMException
				{ // itemxml
					if ((choices == null) || (choices.length == 0))
						throw new CMException("NO choices?!");
					if (!(str instanceof String))
						throw new CMException("Bad type: " + ((str == null) ? "null" : str.getClass().getName()));
					StringBuffer choiceNames = new StringBuffer("");
					for (final Object choice : choices)
						choiceNames.append(((Environmental) choice).Name() + ", ");
					if (choiceNames.toString().endsWith(", "))
						choiceNames = new StringBuffer(choiceNames.substring(0, choiceNames.length() - 2));
					if (((String) str).trim().length() == 0)
					{
						if (emptyOK)
							return "";
						throw new CMException("You must enter one of the following: " + choiceNames.toString());
					}
					final Environmental[] ES = new Environmental[choices.length];
					for (int e = 0; e < choices.length; e++)
						ES[e] = (Environmental) choices[e];
					final Environmental E = CMLib.english().fetchEnvironmental(Arrays.asList(ES), (String) str, false);
					if (E == null)
						throw new CMException("'" + str + "' was not found.  You must enter one of the following: " + choiceNames.toString());
					return CMLib.english().getContextName(ES, E);
				}
			};
		case $STRING:
			return new GenericEditor.CMEval()
			{
				@Override
				public Object eval(Object str, Object[] choices, boolean emptyOK) throws CMException
				{ // string
					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 value!");
					}
					return str;
				}
			};
		case $ROOMID:
			return new GenericEditor.CMEval()
			{
				@Override
				public Object eval(Object str, Object[] choices, boolean emptyOK) throws CMException
				{ // roomid
					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 room id(s), name(s), keyword ANY, or ANY MASK=...");
					}
					if (((String) str).trim().equalsIgnoreCase("ANY"))
						return ((String) str).trim();
					if (((String) str).trim().toUpperCase().startsWith("ANY MASK="))
						return str;
					if (CMStrings.contains(Quest.ROOM_REFERENCE_QCODES, ((String) str).toUpperCase().trim()))
						return ((String) str).toUpperCase().trim();
					if ((((String) str).indexOf(' ') > 0) && (((String) str).indexOf('\"') < 0))
						throw new CMException(
								"Multiple-word room names/ids must be grouped with double-quotes.  If this represents several names, put each name in double-quotes as so: \"name1\" \"name2\" \"multi word name\".");
					final Vector<String> V = CMParms.parse((String) str);
					if (V.size() == 0)
					{
						if (emptyOK)
							return "";
						throw new CMException("You must enter an room id(s), name(s), keyword ANY, or ANY MASK=...");
					}
					String s = null;
					for (int v = 0; v < V.size(); v++)
					{
						s = V.elementAt(v);
						boolean found = false;
						final Room R = CMLib.map().getRoom(s);
						if (R != null)
							found = true;
						if (!found)
							found = CMLib.map().findWorldRoomLiberally(null, s, "R", 50, 30000) != null;
						if (!found)
							throw new CMException("'" + (V.elementAt(v)) + "' is not a valid room name, id, or description.");
					}
					return str;
				}
			};
		case $AREA:
			return new GenericEditor.CMEval()
			{
				@Override
				public Object eval(Object str, Object[] choices, boolean emptyOK) throws CMException
				{ // area
					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 area name(s), keyword ANY, or ANY MASK=...");
					}
					if (((String) str).trim().equalsIgnoreCase("ANY"))
						return ((String) str).trim();
					if (((String) str).trim().toUpperCase().startsWith("ANY MASK="))
						return str;
					if ((((String) str).indexOf(' ') > 0) && (((String) str).indexOf('\"') < 0))
						throw new CMException(
								"Multiple-word area names/ids must be grouped with double-quotes.  If this represents several names, put each name in double-quotes as so: \"name1\" \"name2\" \"multi word name\".");
					final Vector<String> V = CMParms.parse((String) str);
					if (V.size() == 0)
					{
						if (emptyOK)
							return "";
						throw new CMException("You must enter an area name(s), keyword ANY, or ANY MASK=...");
					}
					final StringBuffer returnStr = new StringBuffer("");
					for (int v = 0; v < V.size(); v++)
					{
						final Area A = CMLib.map().findArea(V.elementAt(v));
						if (A == null)
							throw new CMException("'" + (V.elementAt(v)) + "' is not a valid area name.");
						returnStr.append("\"" + A.name() + "\" ");
					}
					return returnStr.toString().trim();
				}
			};
		case $MOBXML:
			return new GenericEditor.CMEval()
			{
				@Override
				public Object eval(Object str, Object[] choices, boolean emptyOK) throws CMException
				{ // mobxml
					if ((choices == null) || (choices.length == 0))
						throw new CMException("NO choices?!");
					if (!(str instanceof String))
						throw new CMException("Bad type: " + ((str == null) ? "null" : str.getClass().getName()));
					StringBuffer choiceNames = new StringBuffer("");
					for (final Object choice : choices)
						choiceNames.append(((Environmental) choice).Name() + ", ");
					if (choiceNames.toString().endsWith(", "))
						choiceNames = new StringBuffer(choiceNames.substring(0, choiceNames.length() - 2));
					if (((String) str).trim().length() == 0)
					{
						if (emptyOK)
							return "";
						throw new CMException("You must enter one of the following: " + choiceNames.toString());
					}
					final Environmental[] ES = new Environmental[choices.length];
					for (int e = 0; e < choices.length; e++)
						ES[e] = (Environmental) choices[e];
					final Environmental E = CMLib.english().fetchEnvironmental(Arrays.asList(ES), (String) str, false);
					if (E == null)
						throw new CMException("'" + str + "' was not found.  You must enter one of the following: " + choiceNames.toString());
					return CMLib.english().getContextName(ES, E);
				}
			};
		case $NAME:
			return new GenericEditor.CMEval()
			{
				@Override
				public Object eval(Object str, Object[] choices, boolean emptyOK) throws CMException
				{ // designame
					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 value!");
					}
					if (((String) str).trim().equalsIgnoreCase("ANY"))
						return ((String) str).trim();
					if (((String) str).trim().toUpperCase().startsWith("ANY MASK="))
						return str;
					if ((((String) str).indexOf(' ') > 0) && (((String) str).indexOf('\"') < 0))
						throw new CMException("Multiple-word names must be grouped with double-quotes.  If this represents several names, put each name in double-quotes as so: \"name1\" \"name2\" \"multi word name\".");
					return str;
				}
			};
		case $LONG_STRING:
			return new GenericEditor.CMEval()
			{
				@Override
				public Object eval(Object str, Object[] choices, boolean emptyOK) throws CMException
				{ // string
					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 value!");
					}
					str = CMStrings.replaceAll((String) str, "\n\r", " ");
					str = CMStrings.replaceAll((String) str, "\r\n", " ");
					str = CMStrings.replaceAll((String) str, "\n", " ");
					str = CMStrings.replaceAll((String) str, "\r", " ");
					return str;
				}
			};
		case $MOBXML_ONEORMORE:
			return new GenericEditor.CMEval()
			{
				@Override
				public Object eval(Object str, Object[] choices, boolean emptyOK) throws CMException
				{ // mobxml_1ormore
					final GenericEditor.CMEval evaler = getQuestCommandEval(QMCommand.$MOBXML);
					return evaler.eval(str, choices, emptyOK);
				}
			};
		case $ITEMXML_ONEORMORE:
			return new GenericEditor.CMEval()
			{
				@Override
				public Object eval(Object str, Object[] choices, boolean emptyOK) throws CMException
				{ // itemxml_1ormore
					final GenericEditor.CMEval evaler = getQuestCommandEval(QMCommand.$ITEMXML);
					return evaler.eval(str, choices, emptyOK);
				}
			};
		case $ZAPPERMASK:
			return new GenericEditor.CMEval()
			{
				@Override
				public Object eval(Object str, Object[] choices, boolean emptyOK) throws CMException
				{ // zappermask
					if (!(str instanceof String))
						throw new CMException("Bad type: " + ((str == null) ? "null" : str.getClass().getName()));
					final Vector<String> errors = new Vector<String>(1);
					if (!CMLib.masking().syntaxCheck((String) str, errors))
						throw new CMException("Mask Error: " + CMParms.toListString(errors));
					return str;
				}
			};
		case $ABILITY:
			return new GenericEditor.CMEval()
			{
				@Override
				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;
				}