/
com/planet_ink/coffee_mud/Abilities/Common/
com/planet_ink/coffee_mud/Abilities/Diseases/
com/planet_ink/coffee_mud/Abilities/Druid/
com/planet_ink/coffee_mud/Abilities/Fighter/
com/planet_ink/coffee_mud/Abilities/Languages/
com/planet_ink/coffee_mud/Abilities/Misc/
com/planet_ink/coffee_mud/Abilities/Prayers/
com/planet_ink/coffee_mud/Abilities/Properties/
com/planet_ink/coffee_mud/Abilities/Skills/
com/planet_ink/coffee_mud/Abilities/Songs/
com/planet_ink/coffee_mud/Abilities/Spells/
com/planet_ink/coffee_mud/Abilities/Thief/
com/planet_ink/coffee_mud/Abilities/Traps/
com/planet_ink/coffee_mud/Behaviors/
com/planet_ink/coffee_mud/CharClasses/interfaces/
com/planet_ink/coffee_mud/Commands/
com/planet_ink/coffee_mud/Commands/interfaces/
com/planet_ink/coffee_mud/Common/
com/planet_ink/coffee_mud/Common/interfaces/
com/planet_ink/coffee_mud/Exits/interfaces/
com/planet_ink/coffee_mud/Items/Armor/
com/planet_ink/coffee_mud/Items/Basic/
com/planet_ink/coffee_mud/Items/CompTech/
com/planet_ink/coffee_mud/Items/MiscMagic/
com/planet_ink/coffee_mud/Items/Weapons/
com/planet_ink/coffee_mud/Items/interfaces/
com/planet_ink/coffee_mud/Libraries/
com/planet_ink/coffee_mud/Libraries/interfaces/
com/planet_ink/coffee_mud/Locales/
com/planet_ink/coffee_mud/MOBS/
com/planet_ink/coffee_mud/Races/
com/planet_ink/coffee_mud/Races/interfaces/
com/planet_ink/coffee_mud/WebMacros/
com/planet_ink/coffee_mud/WebMacros/interfaces/
com/planet_ink/coffee_mud/core/
com/planet_ink/coffee_mud/core/collections/
com/planet_ink/coffee_mud/core/interfaces/
com/planet_ink/coffee_mud/core/intermud/
com/planet_ink/coffee_mud/core/intermud/i3/
com/planet_ink/coffee_web/server/
com/planet_ink/siplet/applet/
lib/
resources/factions/
resources/fakedb/
resources/progs/autoplayer/
resources/quests/holidays/
web/
web/admin.templates/
web/admin/grinder/
web/admin/images/
web/clan.templates/
web/pub.templates/
web/pub/images/mxp/
web/pub/sounds/
web/pub/textedit/
package com.planet_ink.coffee_mud.Libraries;
import com.planet_ink.coffee_mud.core.interfaces.*;
import com.planet_ink.coffee_mud.core.exceptions.*;
import com.planet_ink.coffee_mud.core.*;
import com.planet_ink.coffee_mud.core.collections.*;
import com.planet_ink.coffee_mud.Libraries.interfaces.*;
import com.planet_ink.coffee_mud.Libraries.interfaces.MoneyLibrary.MoneyDenomination;
import com.planet_ink.coffee_mud.Abilities.interfaces.*;
import com.planet_ink.coffee_mud.Areas.interfaces.*;
import com.planet_ink.coffee_mud.Behaviors.interfaces.*;
import com.planet_ink.coffee_mud.CharClasses.interfaces.*;
import com.planet_ink.coffee_mud.Commands.interfaces.*;
import com.planet_ink.coffee_mud.Common.interfaces.*;
import com.planet_ink.coffee_mud.Exits.interfaces.*;
import com.planet_ink.coffee_mud.Items.interfaces.*;
import com.planet_ink.coffee_mud.Locales.interfaces.*;
import com.planet_ink.coffee_mud.MOBS.interfaces.*;
import com.planet_ink.coffee_mud.Races.interfaces.*;

import java.io.IOException;
import java.util.*;
import java.util.regex.*;

/*
   Copyright 2003-2016 Bo Zimmerman

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

	   http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/
public class EnglishParser extends StdLibrary implements EnglishParsing
{
	@Override
	public String ID()
	{
		return "EnglishParser";
	}

	private final static String[]			ARTICLES			= { "a", "an", "all of", "some one", "a pair of", "one of", "all", "the", "some", "each" };
	public static boolean[]					PUNCTUATION_TABLE	= null;
	public final static char[]				ALL_CHRS			= "ALL".toCharArray();
	public final static String[]			fwords				= { "calf", "half", "knife", "life", "wife", "elf", "self", "shelf", "leaf", "sheaf", "thief", "loaf", "wolf" };
	public final static List<Environmental>	empty				= new ReadOnlyVector<Environmental>(1);

	@Override
	public String toEnglishStringList(final String[] V)
	{
		if((V==null)||(V.length==0))
		{
			return "";
		}
		if(V.length==1)
			return V[0];
		final StringBuffer s=new StringBuffer("");
		for(int v=0;v<V.length-1;v++)
		{
			if(v>0)
				s.append(", ");
			s.append(V[v]);
		}
		s.append(" and ");
		s.append(V[V.length-1]);
		return s.toString();
	}

	@Override
	public String toEnglishStringList(final Collection<? extends Object> V)
	{
		if((V==null)||(V.isEmpty()))
		{
			return "";
		}
		if(V.size()==1)
			return V.iterator().next().toString();
		final StringBuffer s=new StringBuffer("");
		for(Iterator<? extends Object> o=V.iterator();o.hasNext();)
		{
			if(s.length()>0) 
				s.append(", ");
			final Object O = o.next();
			if(!o.hasNext())
				s.append(" and ");
			s.append(O.toString());
		}
		return s.toString();
	}

	@Override
	public boolean isAnArticle(String s)
	{
		s=s.toLowerCase();
		for (final String article : ARTICLES)
			if(s.equals(article))
				return true;
		return false;
	}

	@Override
	public String makePlural(String str)
	{
		if((str==null)||(str.length()==0))
			return str;
		final boolean uppercase=Character.isUpperCase(str.charAt(str.length()-1));
		final String lowerStr=str.toLowerCase();
		if(lowerStr.endsWith("is"))
			return str.substring(0,str.length()-2)+(uppercase?"ES":"es");
		if(lowerStr.endsWith("s")||lowerStr.endsWith("z")||lowerStr.endsWith("x")||lowerStr.endsWith("ch")||lowerStr.endsWith("sh"))
			return str+(uppercase?"ES":"es");
		if(lowerStr.endsWith("ay")||lowerStr.endsWith("ey")||lowerStr.endsWith("iy")||lowerStr.endsWith("oy")||lowerStr.endsWith("uy"))
			return str+(uppercase?"S":"s");
		if(lowerStr.endsWith("y"))
			return str.substring(0,str.length()-1)+(uppercase?"IES":"ies");
		if(CMStrings.contains(fwords, lowerStr))
			return str.substring(0,str.length()-1)+(uppercase?"VES":"ves");
		return str+(uppercase?"S":"s");
	}
	
	@Override
	public String cleanArticles(String s)
	{
		final String lowStr=s.toLowerCase();
		for (final String article : ARTICLES)
			if(lowStr.startsWith(article+" "))
				return s.substring(article.length()+1);
		return s;
	}

	@Override
	public String properIndefiniteArticle(String str)
	{
		int i=0;
		for(;i<str.length();i++)
		{
			switch(str.charAt(i))
			{
			case '^':
			{
				i++;
				if(i<str.length())
				{
					switch(str.charAt(i))
					{
					case ColorLibrary.COLORCODE_FANSI256:
						i += 3;
						break;
					case ColorLibrary.COLORCODE_BANSI256:
						i += 3;
						break;
					case ColorLibrary.COLORCODE_BACKGROUND:
						i++;
						break;
					case '<':
						while(i<str.length()-1)
						{
							if((str.charAt(i)!='^')||(str.charAt(i+1)!='>'))
								i++;
							else
							{
								i++;
								break;
							}
						}
						break;
					case '&':
						while(i<str.length())
						{
							if(str.charAt(i)!=';')
								i++;
							else
								break;
						}
						break;
					}
				}
				break;
			}
			case 'a':
			case 'e':
			case 'i':
			case 'o':
			case 'u':
			case 'A':
			case 'E':
			case 'I':
			case 'O':
			case 'U':
				return "an";
			default:
				if(Character.isLetter(str.charAt(i)))
					return "a";
				else
					return "";
			}
		}
		return "";
	}

	protected String getBestDistance(long d)
	{
		String min=null;
		final long sign=(long)Math.signum(d);
		d=Math.abs(d);
		for(SpaceObject.Distance distance : SpaceObject.DISTANCES)
		{
			if((distance.dm * 2) < d)
			{
				double val=(double)d/(double)distance.dm;
				if((val<0)||(val<100))
					val=Math.round(val*100.0)/100.0;
				else
					val=Math.round(val);
				if(val!=0.0)
				{
					String s=Double.toString(sign*val);
					if(s.endsWith(".0"))
						s=s.substring(0,s.length()-2);
					s+=distance.abbr;
					min = s;
					break;
					//if((min==null)||(min.length()>s.length())) min=s;
				}
			}
		}
		if(min==null)
			return (sign*d)+"dm";
		return min;
	}
	
	@Override
	public String sizeDescShort(long size)
	{
		return getBestDistance(size);
	}
	
	@Override
	public String distanceDescShort(long distance)
	{
		return getBestDistance(distance);
	}
	
	@Override
	public String coordDescShort(long[] coords)
	{
		return getBestDistance(coords[0])+","+getBestDistance(coords[1])+","+getBestDistance(coords[2]);
	}
	
	@Override
	public String speedDescShort(double speed)
	{
		return getBestDistance(Math.round(speed))+"/sec";
	}
	
	@Override
	public String directionDescShort(double[] dir)
	{
		return Math.round(Math.toDegrees(dir[0])*100)/100.0+" mark "+Math.round(Math.toDegrees(dir[1])*100)/100.0;
	}
	
	@Override
	public Long parseSpaceDistance(String dist)
	{
		if(dist==null)
			return null;
		dist=dist.trim();
		int digits=-1;
		if((dist.length()>0)&&(dist.charAt(0)=='-'))
			digits++;
		while((digits<dist.length()-1)&&(Character.isDigit(dist.charAt(digits+1))))
			digits++;
		if(digits<0)
			return null;
		Long value=Long.valueOf(dist.substring(0,digits+1));
		String unit=dist.substring(digits+1).trim();
		if(unit.length()==0)
			return value;
		SpaceObject.Distance distUnit=(SpaceObject.Distance)CMath.s_valueOf(SpaceObject.Distance.class, unit);
		if(distUnit==null)
		{
			for(SpaceObject.Distance d : SpaceObject.Distance.values())
			{
				if(d.abbr.equalsIgnoreCase(unit))
					distUnit=d;
			}
		}
		if(distUnit==null)
		{
			for(SpaceObject.Distance d : SpaceObject.Distance.values())
			{
				if(d.name().equalsIgnoreCase(unit))
					distUnit=d;
			}
		}
		if(distUnit==null)
		{
			for(SpaceObject.Distance d : SpaceObject.Distance.values())
			{
				if(unit.toLowerCase().startsWith(d.name().toLowerCase()))
					distUnit=d;
			}
		}
		if(distUnit==null)
			return null;
		return new Long(value.longValue() * distUnit.dm);
	}
	
	@Override
	public String getFirstWord(final String str)
	{
		int i=0;
		int start=-1;
		for(;i<str.length();i++)
		switch(str.charAt(i))
		{
		case '^':
		{
			i++;
			if(i<str.length())
			{
				switch(str.charAt(i))
				{
				case ColorLibrary.COLORCODE_FANSI256:
					i += 3;
					break;
				case ColorLibrary.COLORCODE_BANSI256:
					i += 3;
					break;
				case ColorLibrary.COLORCODE_BACKGROUND:
					i++;
					break;
				case '<':
					while(i<str.length()-1)
					{
						if((str.charAt(i)!='^')||(str.charAt(i+1)!='>'))
							i++;
						else
						{
							i++;
							break;
						}
					}
					break;
				case '&':
					while(i<str.length())
					{
						if(str.charAt(i)!=';')
							i++;
						else
							break;
					}
					break;
				}
			}
			break;
		}
		case ' ':
			if(start>=0)
				return str.substring(start,i);
			break;
		default:
			if(Character.isLetter(str.charAt(i)) && (start<0))
				start=i;
			break;
		}
		return str;
	}

	@Override
	public String startWithAorAn(final String str)
	{
		if((str==null)||(str.length()==0))
			return str;
		final String uppStr=getFirstWord(str).toUpperCase();
		if((!uppStr.equals("A")) &&(!uppStr.equals("AN"))
		&&(!uppStr.equals("THE")) &&(!uppStr.equals("SOME")))
			return (properIndefiniteArticle(str)+" "+str.trim()).trim();
		return str;
	}


	@Override
	public boolean startsWithAnArticle(String s)
	{
		return isAnArticle(getFirstWord(s));
	}
	
	@Override
	public String insertUnColoredAdjective(String str, String adjective)
	{
		if(str.length()==0)
			return str;
		str=CMStrings.removeColors(str.trim());
		final String uppStr=str.toUpperCase();
		if((uppStr.startsWith("A "))
		||(uppStr.startsWith("AN ")))
			return properIndefiniteArticle(adjective)+" "+adjective+" "+str.substring(2).trim();
		if(uppStr.startsWith("THE "))
			return properIndefiniteArticle(adjective)+" "+adjective+" "+str.substring(3).trim();
		if(uppStr.startsWith("SOME "))
			return properIndefiniteArticle(adjective)+" "+adjective+" "+str.substring(4).trim();
		return properIndefiniteArticle(adjective)+" "+adjective+" "+str.trim();
	}

	@Override
	public CMObject findCommand(MOB mob, List<String> commands)
	{
		if((mob==null)
		||(commands==null)
		||(mob.location()==null)
		||(commands.isEmpty()))
			return null;

		String firstWord=commands.get(0).toUpperCase();

		if((firstWord.length()>1)&&(!Character.isLetterOrDigit(firstWord.charAt(0))))
		{
			commands.add(1,commands.get(0).substring(1));
			commands.set(0,""+firstWord.charAt(0));
			firstWord=""+firstWord.charAt(0);
		}

		// first, exacting pass
		Command C=CMClass.findCommandByTrigger(firstWord,true);
		if((C!=null)
		&&(C.securityCheck(mob))
		&&(!CMSecurity.isCommandDisabled(CMClass.classID(C).toUpperCase())))
			return C;

		Ability A=getToEvoke(mob,new XVector<String>(commands));
		if((A!=null)
		&&(!CMSecurity.isAbilityDisabled(A.ID().toUpperCase())))
			return A;

		if(getAnEvokeWord(mob,firstWord)!=null)
			return null;

		Social social=CMLib.socials().fetchSocial(commands,true,true);
		if(social!=null)
			return social;

		for(int c=0;c<CMLib.channels().getNumChannels();c++)
		{
			final ChannelsLibrary.CMChannel chan=CMLib.channels().getChannel(c);
			if(chan.name().equalsIgnoreCase(firstWord))
			{
				C=CMClass.getCommand("Channel");
				if((C!=null)&&(C.securityCheck(mob)))
					return C;
			}
			else
			if(("NO"+chan.name()).equalsIgnoreCase(firstWord))
			{
				C=CMClass.getCommand("NoChannel");
				if((C!=null)&&(C.securityCheck(mob)))
					return C;
			}
		}

		for(final Enumeration<JournalsLibrary.CommandJournal> e=CMLib.journals().commandJournals();e.hasMoreElements();)
		{
			final JournalsLibrary.CommandJournal CMJ=e.nextElement();
			if(CMJ.NAME().equalsIgnoreCase(firstWord))
			{
				C=CMClass.getCommand("CommandJournal");
				if((C!=null)&&(C.securityCheck(mob)))
					return C;
			}
		}

		// second, inexacting pass
		for(final Enumeration<Ability> a=mob.allAbilities();a.hasMoreElements();)
		{
			A=a.nextElement();
			final HashSet<String> tried=new HashSet<String>();
			if((A!=null)&&(A.triggerStrings()!=null))
			{
				for(int t=0;t<A.triggerStrings().length;t++)
				{
					if((A.triggerStrings()[t].toUpperCase().startsWith(firstWord))
					&&(!tried.contains(A.triggerStrings()[t])))
					{
						final Vector<String> commands2=new XVector<String>(commands);
						commands2.setElementAt(A.triggerStrings()[t],0);
						final Ability A2=getToEvoke(mob,commands2);
						if((A2!=null)&&(!CMSecurity.isAbilityDisabled(A2.ID().toUpperCase())))
						{
							commands.set(0,A.triggerStrings()[t]);
							return A;
						}
					}
				}
			}
		}
		//commands comes inexactly after ables
		//because of CA, PR, etc..
		C=CMClass.findCommandByTrigger(firstWord,false);
		if((C!=null)
		&&(C.securityCheck(mob))
		&&(!CMSecurity.isCommandDisabled(CMClass.classID(C).toUpperCase())))
			return C;


		social=CMLib.socials().fetchSocial(commands,false,true);
		if(social!=null)
		{
			commands.set(0,social.baseName());
			return social;
		}

		for(int c=0;c<CMLib.channels().getNumChannels();c++)
		{
			final ChannelsLibrary.CMChannel chan=CMLib.channels().getChannel(c);
			if(chan.name().startsWith(firstWord))
			{
				commands.set(0,chan.name());
				C=CMClass.getCommand("Channel");
				if((C!=null)&&(C.securityCheck(mob)))
					return C;
			}
			else
			if(("NO"+chan.name()).startsWith(firstWord))
			{
				commands.set(0,"NO"+chan.name());
				C=CMClass.getCommand("NoChannel");
				if((C!=null)&&(C.securityCheck(mob)))
					return C;
			}
		}

		for(final Enumeration<JournalsLibrary.CommandJournal> e=CMLib.journals().commandJournals();e.hasMoreElements();)
		{
			final JournalsLibrary.CommandJournal CMJ=e.nextElement();
			if(CMJ.NAME().startsWith(firstWord))
			{
				C=CMClass.getCommand("CommandJournal");
				if((C!=null)&&(C.securityCheck(mob)))
					return C;
			}
		}
		return null;
	}

	@Override
	public boolean evokedBy(Ability thisAbility, String thisWord)
	{
		for(int i=0;i<thisAbility.triggerStrings().length;i++)
		{
			if(thisAbility.triggerStrings()[i].equalsIgnoreCase(thisWord))
				return true;
		}
		return false;
	}

	private String collapsedName(Ability thisAbility)
	{
		final int x=thisAbility.name().indexOf(' ');
		if(x>=0)
			return CMStrings.replaceAll(thisAbility.name()," ","");
		return thisAbility.Name();
	}

	@Override
	public boolean evokedBy(Ability thisAbility, String thisWord, String secondWord)
	{
		for(int i=0;i<thisAbility.triggerStrings().length;i++)
		{
			if(thisAbility.triggerStrings()[i].equalsIgnoreCase(thisWord))
			{
				if(((thisAbility.name().toUpperCase().startsWith(secondWord)))
				||(collapsedName(thisAbility).toUpperCase().startsWith(secondWord)))
					return true;
			}
		}
		return false;
	}

	@Override
	public String getAnEvokeWord(MOB mob, String word)
	{
		if(mob==null)
			return null;
		Ability A=null;
		final HashSet<String[]> done=new HashSet<String[]>();
		word=word.toUpperCase().trim();
		for(final Enumeration<Ability> a=mob.allAbilities();a.hasMoreElements();)
		{
			A=a.nextElement();
			if((A!=null)
			&&(A.triggerStrings()!=null)
			&&(!done.contains(A.triggerStrings())))
			{
				done.add(A.triggerStrings());
				for(int t=0;t<A.triggerStrings().length;t++)
				{
					if(word.equals(A.triggerStrings()[t]))
					{
						if((t>0)&&(A.triggerStrings()[0].startsWith(word)))
							return A.triggerStrings()[0];
						else
							return A.triggerStrings()[t];
					}
				}
			}
		}
		return null;
	}

	@Override
	public Ability getToEvoke(MOB mob, List<String> commands)
	{
		final String evokeWord=commands.get(0).toUpperCase();

		boolean foundMoreThanOne=false;
		Ability evokableAbility=null;
		for(final Enumeration<Ability> a=mob.allAbilities();a.hasMoreElements();)
		{
			final Ability A=a.nextElement();
			if((A!=null)
			&&(evokedBy(A,evokeWord)))
			{
				if((evokableAbility!=null)&&(!A.ID().equals(evokableAbility.ID())))
				{
					foundMoreThanOne=true;
					evokableAbility=null;
					break;
				}
				evokableAbility=A;
			}
		}

		if((evokableAbility!=null)&&(commands.size()>1))
		{
			final int classCode=evokableAbility.classificationCode()&Ability.ALL_ACODES;
			switch(classCode)
			{
			case Ability.ACODE_SPELL:
			case Ability.ACODE_SONG:
			case Ability.ACODE_PRAYER:
			case Ability.ACODE_CHANT:
				evokableAbility=null;
				foundMoreThanOne=true;
				break;
			default:
				break;
			}
		}

		if(evokableAbility!=null)
			commands.remove(0);
		else
		if((foundMoreThanOne)&&(commands.size()>1))
		{
			commands.remove(0);
			foundMoreThanOne=false;
			final String secondWord=commands.get(0).toUpperCase();
			for(final Enumeration<Ability> a=mob.allAbilities();a.hasMoreElements();)
			{
				final Ability A=a.nextElement();
				if((A!=null)
				&&(evokedBy(A,evokeWord,secondWord.toUpperCase())))
				{
					if((A.name().equalsIgnoreCase(secondWord))
					||(collapsedName(A).equalsIgnoreCase(secondWord)))
					{
						evokableAbility=A;
						foundMoreThanOne=false;
						break;
					}
					else
					if((evokableAbility!=null)&&(!A.ID().equals(evokableAbility.ID())))
						foundMoreThanOne=true;
					else
						evokableAbility=A;
				}
			}
			if((evokableAbility!=null)&&(!foundMoreThanOne))
				commands.remove(0);
			else
			if((foundMoreThanOne)&&(commands.size()>1))
			{
				final String secondAndThirdWord=secondWord+" "+commands.get(1).toUpperCase();

				for(final Enumeration<Ability> a=mob.allAbilities();a.hasMoreElements();)
				{
					final Ability A=a.nextElement();
					if((A!=null) && (evokedBy(A,evokeWord,secondAndThirdWord.toUpperCase())))
					{
						evokableAbility=A;
						break;
					}
				}
				if(evokableAbility!=null)
				{
					commands.remove(0);
					commands.remove(0);
				}
			}
			else
			{
				for(final Enumeration<Ability> a=mob.allAbilities();a.hasMoreElements();)
				{
					final Ability A=a.nextElement();
					if((A!=null)
					&&(evokedBy(A,evokeWord))
					&&(A.name().toUpperCase().indexOf(" "+secondWord.toUpperCase())>0))
					{
						evokableAbility=A;
						commands.remove(0);
						break;
					}
				}
			}
		}
		return evokableAbility;
	}

	@Override
	public boolean preEvoke(MOB mob, List<String> commands, int secondsElapsed, double actionsRemaining)
	{
		commands=new Vector<String>(commands);
		final Ability evokableAbility=getToEvoke(mob,commands);
		if(evokableAbility==null)
		{
			mob.tell(L("You don't know how to do that."));
			return false;
		}
		if((CMLib.ableMapper().qualifyingLevel(mob,evokableAbility)>=0)
		&&(!CMLib.ableMapper().qualifiesByLevel(mob,evokableAbility))
		&&(!CMSecurity.isAllowed(mob,mob.location(),CMSecurity.SecFlag.ALLSKILLS)))
		{
			mob.tell(L("You are not high enough level to do that."));
			return false;
		}
		return evokableAbility.preInvoke(mob,commands,null,false,0,secondsElapsed,actionsRemaining);
	}
	
	@Override
	public void evoke(MOB mob, Vector<String> commands)
	{
		final Ability evokableAbility=getToEvoke(mob,commands);
		if(evokableAbility==null)
		{
			mob.tell(L("You don't know how to do that."));
			return;
		}
		if((CMLib.ableMapper().qualifyingLevel(mob,evokableAbility)>=0)
		&&(!CMLib.ableMapper().qualifiesByLevel(mob,evokableAbility))
		&&(!CMSecurity.isAllowed(mob,mob.location(),CMSecurity.SecFlag.ALLSKILLS)))
		{
			mob.tell(L("You are not high enough level to do that."));
			return;
		}
		evokableAbility.invoke(mob,commands,null,false,0);
	}

	private boolean[] PUNCTUATION_TABLE()
	{
		if(PUNCTUATION_TABLE==null)
		{
			final boolean[] PUNCTUATION_TEMP_TABLE=new boolean[255];
			for(int c=0;c<255;c++)
				switch(c)
				{
				case '`': case '~': case '!': case '@': case '#': case '$': case '%':
				case '^': case '&': case '*': case '(': case ')': case '_': case '-':
				case '+': case '=': case '[': case ']': case '{': case '}': case '\\':
				case '|': case ';': case ':': case '\'': case '\"': case ',': case '<':
				case '.': case '>': case '/': case '?':
					PUNCTUATION_TEMP_TABLE[c]=true;
					break;
				default:
					PUNCTUATION_TEMP_TABLE[c]=false;
				}
			PUNCTUATION_TABLE=PUNCTUATION_TEMP_TABLE;
		}
		return PUNCTUATION_TABLE;
	}

	private boolean isPunctuation(final byte b)
	{
		if((b<0)||(b>255))
			return false;
		return PUNCTUATION_TABLE[b];
	}

	@Override
	public boolean hasPunctuation(String str)
	{
		if((str==null)||(str.length()==0))
			return false;
		boolean puncFound=false;
		PUNCTUATION_TABLE();
		for(int x=0;x<str.length();x++)
		{
			if(isPunctuation((byte)str.charAt(x)))
			{
				puncFound=true;
				break;
			}
		}
		return puncFound;
	}
	
	@Override
	public String stripPunctuation(String str)
	{
		if(!hasPunctuation(str))
			return str;
		final char[] strc=str.toCharArray();
		final char[] str2=new char[strc.length];
		int s=0;
		for(int x=0;x<strc.length;x++)
		{
			if(!isPunctuation((byte)strc[x]))
			{
				str2[s]=strc[x];
				s++;
			}
		}
		return new String(str2,0,s);
	}

	@Override
	public List<String> parseWords(final String thisStr)
	{
		if((thisStr==null)||(thisStr.length()==0))
			return new Vector<String>(1);
		return CMParms.parseSpaces(CMLib.english().stripPunctuation(thisStr), true);
	}

	
	public boolean equalsPunctuationless(char[] strC, char[] str2C)
	{
		if((strC.length==0)&&(str2C.length==0))
			return true;
		PUNCTUATION_TABLE();
		int s1=0;
		int s2=0;
		int s1len=strC.length;
		while((s1len>0)&&(Character.isWhitespace(strC[s1len-1])||isPunctuation((byte)strC[s1len-1])))
			s1len--;
		int s2len=str2C.length;
		while((s2len>0)&&(Character.isWhitespace(str2C[s2len-1])||isPunctuation((byte)str2C[s2len-1])))
			s2len--;
		while(s1<s1len)
		{
			while((s1<s1len)&&(isPunctuation((byte)strC[s1])))
				s1++;
			while((s2<s2len)&&(isPunctuation((byte)str2C[s2])))
				s2++;
			if(s1==s1len)
			{
				if(s2==s2len)
					return true;
				return false;
			}
			if(s2==s2len)
				return false;
			if(strC[s1]!=str2C[s2])
				return false;
			s1++;
			s2++;
		}
		if(s2==s2len)
			return true;
		return false;
	}

	@Override
	public boolean containsString(final String toSrchStr, final String srchStr)
	{
		if((toSrchStr==null)||(srchStr==null))
			return false;
		if((toSrchStr.length()==0)&&(srchStr.length()>0))
			return false;
		char[] srchC=srchStr.toCharArray();
		final char[] toSrchC=toSrchStr.toCharArray();
		for(int c=0;c<srchC.length;c++)
			srchC[c]=Character.toUpperCase(srchC[c]);
		for(int c=0;c<toSrchC.length;c++)
			toSrchC[c]=Character.toUpperCase(toSrchC[c]);
		if(java.util.Arrays.equals(srchC,ALL_CHRS))
			return true;
		if(java.util.Arrays.equals(srchC,toSrchC))
			return true;
		if(equalsPunctuationless(srchC,toSrchC))
			return true;

		boolean topOnly=false;
		if((srchC.length>1)&&(srchC[0]=='$'))
		{
			srchC=new String(srchC,1,srchC.length-1).toCharArray();
			topOnly=true;
		}
		int tos=0;
		boolean found=false;
		while((!found)&&(tos<toSrchC.length))
		{
			for(int x=0;x<srchC.length;x++)
			{
				if(tos>=toSrchC.length)
				{
					if(srchC[x]=='$')
						found=true;
					break;
				}

				switch(toSrchC[tos])
				{
				case '^':
					tos++;
					if(tos<toSrchC.length)
					{
						switch(toSrchC[tos])
						{
						case ColorLibrary.COLORCODE_BACKGROUND:
							if(tos < toSrchC.length-1)
								tos+=2;
							break;
						case ColorLibrary.COLORCODE_FANSI256:
						case ColorLibrary.COLORCODE_BANSI256:
							if(tos < toSrchC.length-4)
								tos+=4;
							break;
						default:
							tos++;
							break;
						}
					}
					break;
				case ',':
				case '?':
				case '!':
				case '.':
				case ';':
					tos++;
					break;
				}
				switch(srchC[x])
				{
				case '^':
					x++;
					if(x<srchC.length)
					{
						switch(srchC[x])
						{
						case ColorLibrary.COLORCODE_BACKGROUND:
							if(x < srchC.length-1)
								x+=2;
							break;
						case ColorLibrary.COLORCODE_FANSI256:
						case ColorLibrary.COLORCODE_BANSI256:
							if(x < srchC.length-4)
								x+=4;
							break;
						default:
							x++;
							break;
						}
					}
					break;
				case ',':
				case '?':
				case '!':
				case '.':
				case ';': x++;
					break;
				}
				if(x<srchC.length)
				{
					if(tos<toSrchC.length)
					{
						if(srchC[x]!=toSrchC[tos])
							break;
						else
						if(x==(srchC.length-1))
							 found=true;
						else
							tos++;
					}
					else
					if(srchC[x]=='$')
						found=true;
					else
						break;
				}
				else
				{
					found=true;
					break;
				}
			}
			if((topOnly)&&(!found))
				break;
			while((!found)&&(tos<toSrchC.length)&&(Character.isLetter(toSrchC[tos])))
				tos++;
			tos++;
		}
		return found;
	}
	
	@Override
	public String bumpDotNumber(String srchStr)
	{
		final FetchFlags flags=fetchFlags(srchStr);
		if(flags==null)
			return srchStr;
		if(flags.allFlag)
			return srchStr;
		if(flags.occurrance==0)
			return "1."+flags.srchStr;
		return (flags.occurrance+1)+"."+flags.srchStr;
	}

	@Override
	public int getContextNumber(ItemCollection cont, Environmental E)
	{
		return getContextNumber(toCollection(cont),E);
	}
	
	@Override
	public int getContextNumber(Environmental[] list, Environmental E)
	{
		return getContextNumber(new XVector<Environmental>(list),E);
	}
	
	@Override
	public int getContextNumber(Collection<? extends Environmental> list, Environmental E)
	{
		if(list==null)
			return 0;
		int context=1;
		for(final Object O : list)
		{
			if((((Environmental)O).Name().equalsIgnoreCase(E.Name()))
			||(((Environmental)O).name().equalsIgnoreCase(E.name())))
			{
				if(O==E)
					return context<2?0:context;
				if((!(O instanceof Item))
				||(!(E instanceof Item))
				||(((Item)E).container()==((Item)O).container()))
					context++;
			}
		}
		return -1;
	}
	
	private Collection<? extends Environmental> toCollection(ItemCollection cont)
	{
		final LinkedList<Item> list=new LinkedList<Item>();
		for(final Enumeration<Item> i=cont.items();i.hasMoreElements();)
			list.add(i.nextElement());
		return list;
	}

	@Override
	public int getContextSameNumber(ItemCollection cont, Environmental E)
	{
		return getContextSameNumber(toCollection(cont),E);
	}
	
	@Override
	public int getContextSameNumber(Environmental[] list, Environmental E)
	{
		return getContextSameNumber(new XVector<Environmental>(list),E);
	}
	
	@Override
	public int getContextSameNumber(Collection<? extends Environmental> list, Environmental E)
	{
		if(list==null)
			return 0;
		int context=1;
		for(final Object O : list)
		{
			if((((Environmental)O).Name().equalsIgnoreCase(E.Name()))
			||(((Environmental)O).name().equalsIgnoreCase(E.name())))
			{
				if(E.sameAs((Environmental)O))
					return context<2?0:context;
				if((!(O instanceof Item))
				||(!(E instanceof Item))
				||(((Item)E).container()==((Item)O).container()))
					context++;
			}
		}
		return -1;
	}
	
	@Override
	public String getContextName(ItemCollection cont, Environmental E)
	{
		return getContextName(toCollection(cont),E);
	}
	
	@Override
	public String getContextName(Environmental[] list, Environmental E)
	{
		return getContextName(new XVector<Environmental>(list),E);
	}
	
	@Override
	public String getContextName(Collection<? extends Environmental> list, Environmental E)
	{
		if(list==null) 
			return E.name();
		final int number=getContextNumber(list,E);
		if(number<0) 
			return null;
		if(number<2) 
			return E.name();
		return E.name()+"."+number;
	}

	@Override 
	public String getContextSameName(ItemCollection cont, Environmental E)
	{
		return getContextSameName(toCollection(cont),E);
	}
	
	@Override
	public String getContextSameName(Environmental[] list, Environmental E)
	{
		return getContextSameName(new XVector<Environmental>(list),E);
	}
	
	@Override
	public String getContextSameName(Collection<? extends Environmental> list, Environmental E)
	{
		if(list==null)
			return E.name();
		final int number=getContextSameNumber(list,E);
		if(number<0)
			return null;
		if(number<2)
			return E.name();
		return E.name()+"."+number;
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public Environmental parseShopkeeper(MOB mob, List<String> commands, String error)
	{
		if(commands.isEmpty())
		{
			if(error.length()>0)
				mob.tell(error);
			return null;
		}
		commands.remove(0);

		final List<Environmental> V=CMLib.coffeeShops().getAllShopkeepers(mob.location(),mob);
		if(V.isEmpty())
		{
			if(error.length()>0)
				mob.tell(error);
			return null;
		}
		if(V.size()>1)
		{
			if(commands.size()<2)
			{
				if(error.length()>0)
					mob.tell(error);
				return null;
			}
			final String what=commands.get(commands.size()-1);

			Environmental shopkeeper=fetchEnvironmental(V,what,false);
			if((shopkeeper==null)&&(what.equals("shop")||what.equals("the shop")))
			{
				for(int v=0;v<V.size();v++)
				{
					if(V.get(v) instanceof Area)
					{
						shopkeeper = V.get(v);
						break;
					}
				}
			}
			if((shopkeeper!=null)&&(CMLib.coffeeShops().getShopKeeper(shopkeeper)!=null)&&(CMLib.flags().canBeSeenBy(shopkeeper,mob)))
				commands.remove(commands.size()-1);
			else
			{
				CMLib.commands().doCommandFail(mob,new XVector(commands),L("You don't see anyone called '@x1' here buying or selling.",commands.get(commands.size()-1)));
				return null;
			}
			return shopkeeper;
		}
		Environmental shopkeeper=V.get(0);
		if(commands.size()>1)
		{
			final MOB M=mob.location().fetchInhabitant(commands.get(commands.size()-1));
			if((M!=null)&&(CMLib.coffeeShops().getShopKeeper(M)!=null)&&(CMLib.flags().canBeSeenBy(M,mob)))
			{
				shopkeeper=M;
				commands.remove(commands.size()-1);
			}
		}
		return shopkeeper;
	}

	@Override
	public List<Item> fetchItemList(Environmental from,
									MOB mob,
									Item container,
									List<String> commands,
									Filterer<Environmental> filter,
									boolean visionMatters)
	{
		int addendum=1;
		String addendumStr="";
		List<Item> V=new Vector<Item>();

		int maxToItem=Integer.MAX_VALUE;
		if((commands.size()>1)
		&&(CMath.s_int(commands.get(0))>0))
		{
			maxToItem=CMath.s_int(commands.get(0));
			commands.set(0,"all");
		}

		String name=CMParms.combine(commands,0);
		boolean allFlag = (!commands.isEmpty()) ? commands.get(0).equalsIgnoreCase("all") : false;
		if (name.toUpperCase().startsWith("ALL."))
		{
			allFlag = true;
			name = "ALL " + name.substring(4);
		}
		if (name.toUpperCase().endsWith(".ALL"))
		{
			allFlag = true;
			name = "ALL " + name.substring(0, name.length() - 4);
		}
		boolean doBugFix = true;
		boolean wornOnly = true;
		boolean unwornOnly = true;
		while(doBugFix || ((allFlag)&&(addendum<=maxToItem)))
		{
			doBugFix=false;
			Environmental item=null;
			if(from instanceof MOB)
				item=((MOB)from).fetchItem(container,filter,name+addendumStr);
			else
			if(from instanceof Room)
				item=((Room)from).fetchFromMOBRoomFavorsItems(mob,container,name+addendumStr,filter);
			if((item!=null)
			&&(item instanceof Item)
			&&((!visionMatters)||(CMLib.flags().canBeSeenBy(item,mob))||(item instanceof Light))
			&&(!V.contains(item)))
			{
				V.add((Item)item);
				if(((Item)item).amWearingAt(Wearable.IN_INVENTORY))
					wornOnly=false;
				else
					unwornOnly=false;
			}
			if(item==null)
				break;
			addendumStr="."+(++addendum);
		}

		if(wornOnly && (!V.isEmpty()))
		{
			final Vector<Item> V2=new Vector<Item>();
			short topLayer=0;
			short curLayer=0;
			int which=-1;
			while(!V.isEmpty())
			{
				Item I=V.get(0);
				topLayer=(I instanceof Armor)?((Armor)I).getClothingLayer():0;
				which=0;
				for(int v=1;v<V.size();v++)
				{
					I=V.get(v);
					curLayer=(I instanceof Armor)?((Armor)I).getClothingLayer():0;
					if(curLayer>topLayer)
					{ which=v; topLayer=curLayer;}
				}
				V2.addElement(V.get(which));
				V.remove(which);
			}
			V=V2;
		}
		else
		if(unwornOnly && (!V.isEmpty()))
		{
			final Vector<Item> V2=new Vector<Item>();
			short topLayer=0;
			short curLayer=0;
			int which=-1;
			while(!V.isEmpty())
			{
				Item I=V.get(0);
				topLayer=(I instanceof Armor)?((Armor)I).getClothingLayer():0;
				which=0;
				for(int v=1;v<V.size();v++)
				{
					I=V.get(v);
					curLayer=(I instanceof Armor)?((Armor)I).getClothingLayer():0;
					if(curLayer<topLayer)
					{ which=v; topLayer=curLayer;}
				}
				V2.addElement(V.get(which));
				V.remove(which);
			}
			V=V2;
		}
		return V;
	}

	@Override
	public long numPossibleGold(Environmental mine, String itemID)
	{
		if(itemID.toUpperCase().trim().startsWith("A PILE OF "))
			itemID=itemID.substring(10);
		if(CMath.isInteger(itemID))
		{
			final long num=CMath.s_long(itemID);
			if(mine instanceof MOB)
			{
				List<Coins> V=CMLib.beanCounter().getStandardCurrency((MOB)mine,CMLib.beanCounter().getCurrency(mine));
				for(int v=0;v<V.size();v++)
					if(V.get(v).getNumberOfCoins()>=num)
						return num;
				V=CMLib.beanCounter().getStandardCurrency((MOB)mine,null);
				for(int v=0;v<V.size();v++)
					if(V.get(v).getNumberOfCoins()>=num)
						return num;
			}
			return CMath.s_long(itemID);
		}
		final Vector<String> V=CMParms.parse(itemID);
		if((V.size()>1)
		&&((CMath.isInteger(V.firstElement()))
		&&(matchAnyCurrencySet(CMParms.combine(V,1))!=null)))
			return CMath.s_long(V.firstElement());
		else
		if((V.size()>1)&&(V.firstElement().equalsIgnoreCase("all")))
		{
			final String currency=matchAnyCurrencySet(CMParms.combine(V,1));
			if(currency!=null)
			{
				if(mine instanceof MOB)
				{
					final List<Coins> V2=CMLib.beanCounter().getStandardCurrency((MOB)mine,currency);
					final double denomination=matchAnyDenomination(currency,CMParms.combine(V,1));
					Coins C=null;
					for(int v2=0;v2<V2.size();v2++)
					{
						C=V2.get(v2);
						if(C.getDenomination()==denomination)
							return C.getNumberOfCoins();
					}
				}
				return 1;
			}
		}
		else
		if((!V.isEmpty())&&(matchAnyCurrencySet(CMParms.combine(V,0))!=null))
			return 1;
		return 0;
	}

	@Override
	public String numPossibleGoldCurrency(Environmental mine, String itemID)
	{
		if(itemID.toUpperCase().trim().startsWith("A PILE OF "))
			itemID=itemID.substring(10);
		if(CMath.isInteger(itemID))
		{
			final long num=CMath.s_long(itemID);
			if(mine instanceof MOB)
			{
				List<Coins> V=CMLib.beanCounter().getStandardCurrency((MOB)mine,CMLib.beanCounter().getCurrency(mine));
				for(int v=0;v<V.size();v++)
				{
					if(V.get(v).getNumberOfCoins()>=num)
						return V.get(v).getCurrency();
				}
				V=CMLib.beanCounter().getStandardCurrency((MOB)mine,null);
				for(int v=0;v<V.size();v++)
				{
					if(V.get(v).getNumberOfCoins()>=num)
						return V.get(v).getCurrency();
				}
			}
			return CMLib.beanCounter().getCurrency(mine);
		}
		final Vector<String> V=CMParms.parse(itemID);
		if((V.size()>1)&&(CMath.isInteger(V.firstElement())))
			return matchAnyCurrencySet(CMParms.combine(V,1));
		else
		if((V.size()>1)&&(V.firstElement().equalsIgnoreCase("all")))
			return matchAnyCurrencySet(CMParms.combine(V,1));
		else
		if(!V.isEmpty())
			return matchAnyCurrencySet(CMParms.combine(V,0));
		return CMLib.beanCounter().getCurrency(mine);
	}

	@Override
	public long getMillisMultiplierByName(String timeName)
	{
		timeName=timeName.toLowerCase();
		if("ticks".startsWith(timeName))
			return CMProps.getTickMillis();
		else
		if("seconds".startsWith(timeName))
			return 1000;
		else
		if("minutes".startsWith(timeName))
			return 1000*60;
		else
		if("hours".startsWith(timeName))
			return 1000*60*60;
		else
		if("days".startsWith(timeName))
			return 1000*60*60*24;
		else
		if("weeks".startsWith(timeName))
			return 1000*60*60*24*7;
		else
			return -1;
	}

	@Override
	public double numPossibleGoldDenomination(Environmental mine, String currency, String itemID)
	{
		if(itemID.toUpperCase().trim().startsWith("A PILE OF "))
			itemID=itemID.substring(10);
		if(CMath.isInteger(itemID))
		{
			final long num=CMath.s_long(itemID);
			if(mine instanceof MOB)
			{
				final List<Coins> V=CMLib.beanCounter().getStandardCurrency((MOB)mine,currency);
				for(int v=0;v<V.size();v++)
				{
					if(V.get(v).getNumberOfCoins()>=num)
						return V.get(v).getDenomination();
				}
			}
			return CMLib.beanCounter().getLowestDenomination(currency);
		}
		final Vector<String> V=CMParms.parse(itemID);
		if((V.size()>1)&&(CMath.isInteger(V.firstElement())))
			return matchAnyDenomination(currency,CMParms.combine(V,1));
		else
		if((V.size()>1)&&(V.firstElement().equalsIgnoreCase("all")))
			return matchAnyDenomination(currency,CMParms.combine(V,1));
		else
		if(!V.isEmpty())
			return matchAnyDenomination(currency,CMParms.combine(V,0));
		return 0;
	}

	@Override
	public String matchAnyCurrencySet(String itemID)
	{
		final List<String> V=CMLib.beanCounter().getAllCurrencies();
		List<String> V2=null;
		for(int v=0;v<V.size();v++)
		{
			V2=CMLib.beanCounter().getDenominationNameSet(V.get(v));
			for(int v2=0;v2<V2.size();v2++)
			{
				String s=V2.get(v2);
				if(s.toLowerCase().endsWith("(s)"))
					s=s.substring(0,s.length()-3)+"s";
				if(containsString(s,itemID))
					return V.get(v);
			}
		}
		return null;
	}

	@Override
	public double matchAnyDenomination(String currency, String itemID)
	{
		final MoneyLibrary.MoneyDenomination[] DV=CMLib.beanCounter().getCurrencySet(currency);
		itemID=itemID.toUpperCase();
		String s=null;
		if(DV!=null)
		{
			for (final MoneyDenomination element : DV)
			{
				s=element.name().toUpperCase();
				if(s.endsWith("(S)"))
					s=s.substring(0,s.length()-3)+"S";
				if(containsString(s,itemID))
					return element.value();
				else
				if((s.length()>0)
				&&(containsString(s,itemID)))
					return element.value();
			}
		}
		return 0.0;
	}

	@Override
	public Item possibleRoomGold(MOB seer, Room room, Container container, String itemID)
	{
		if(itemID.toUpperCase().trim().startsWith("A PILE OF "))
			itemID=itemID.substring(10);
		long gold=0;
		if(CMath.isInteger(itemID))
		{
			gold=CMath.s_long(itemID);
			itemID="";
		}
		else
		{
			final Vector<String> V=CMParms.parse(itemID);
			if((V.size()>1)&&(CMath.isInteger(V.firstElement())))
				gold=CMath.s_long(V.firstElement());
			else
				return null;
			itemID=CMParms.combine(V,1);
		}
		if(gold>0)
		{
			for(int i=0;i<room.numItems();i++)
			{
				final Item I=room.getItem(i);
				if((I.container()==container)
				&&(I instanceof Coins)
				&&(CMLib.flags().canBeSeenBy(I,seer))
				&&((itemID.length()==0)||(containsString(I.name(),itemID))))
				{
					if(((Coins)I).getNumberOfCoins()<=gold)
						return I;
					((Coins)I).setNumberOfCoins(((Coins)I).getNumberOfCoins()-gold);
					final Coins C=(Coins)CMClass.getItem("StdCoins");
					C.setCurrency(((Coins)I).getCurrency());
					C.setNumberOfCoins(gold);
					C.setDenomination(((Coins)I).getDenomination());
					C.setContainer(container);
					C.recoverPhyStats();
					room.addItem(C);
					C.setExpirationDate(I.expirationDate());
					return C;
				}
			}
		}
		return null;
	}

	@Override
	public Item bestPossibleGold(MOB mob, Container container, String itemID)
	{
		if(itemID.toUpperCase().trim().startsWith("A PILE OF "))
			itemID=itemID.substring(10);
		long gold=0;
		double denomination=0.0;
		String currency=CMLib.beanCounter().getCurrency(mob);
		if(CMath.isInteger(itemID))
		{
			gold=CMath.s_long(itemID);
			final double totalAmount=CMLib.beanCounter().getTotalAbsoluteValue(mob,currency);
			double bestDenomination=CMLib.beanCounter().getBestDenomination(currency,(int)gold,totalAmount);
			if(bestDenomination==0.0)
			{
				bestDenomination=CMLib.beanCounter().getBestDenomination(null,(int)gold,totalAmount);
				if(bestDenomination>0.0)
					currency=null;
			}
			if(bestDenomination==0.0)
				return null;
			denomination=bestDenomination;
		}
		else
		{
			final Vector<String> V=CMParms.parse(itemID);
			if(V.size()<1)
				return null;
			if((!CMath.isInteger(V.firstElement()))
			&&(!V.firstElement().equalsIgnoreCase("all")))
				V.insertElementAt("1",0);
			final Item I=mob.findItem(container,CMParms.combine(V,1));
			if(I instanceof Coins)
			{
				if(V.firstElement().equalsIgnoreCase("all"))
					gold=((Coins)I).getNumberOfCoins();
				else
					gold=CMath.s_long(V.firstElement());
				currency=((Coins)I).getCurrency();
				denomination=((Coins)I).getDenomination();
			}
			else
				return null;
		}
		if(gold>0)
		{
			final double amt = CMLib.beanCounter().getTotalAbsoluteValue(mob, currency);
			if(amt>=CMath.mul(denomination,gold))
			{
				final double expectedAmt = amt - CMath.mul(denomination,gold);
				CMLib.beanCounter().subtractMoney(mob,currency,denomination,CMath.mul(denomination,gold));
				final double newAmt = CMLib.beanCounter().getTotalAbsoluteValue(mob, currency);
				if(newAmt > expectedAmt)
					CMLib.beanCounter().subtractMoney(mob,currency,(newAmt - expectedAmt));
				final Coins C=(Coins)CMClass.getItem("StdCoins");
				C.setCurrency(currency);
				C.setDenomination(denomination);
				C.setNumberOfCoins(gold);
				C.recoverPhyStats();
				mob.addItem(C);
				return C;
			}
			mob.tell(L("You don't have that much @x1.",CMLib.beanCounter().getDenominationName(currency,denomination)));
			final List<Coins> V=CMLib.beanCounter().getStandardCurrency(mob,currency);
			for(int v=0;v<V.size();v++)
			{
				if(V.get(v).getDenomination()==denomination)
					return V.get(v);
			}
		}
		return null;
	}

	@Override
	public List<Container> possibleContainers(MOB mob, List<String> commands, Filterer<Environmental> filter, boolean withContentOnly)
	{
		final Vector<Container> V=new Vector<Container>(1);
		if(commands.size()==1)
			return V;

		int fromDex=-1;
		int containerDex=commands.size()-1;
		for(int i=commands.size()-2;i>0;i--)
		{
			if(commands.get(i).equalsIgnoreCase("from"))
			{
				fromDex=i;
				containerDex=i+1;
				if(((containerDex+1)<commands.size())
				&&((commands.get(containerDex).equalsIgnoreCase("all"))
					||(CMath.s_int(commands.get(containerDex))>0)))
					containerDex++;
				break;
			}
		}

		String possibleContainerID=CMParms.combine(commands,containerDex);

		boolean allFlag=false;
		String preWord="";
		if(possibleContainerID.equalsIgnoreCase("all"))
			allFlag=true;
		else
		if(containerDex>1)
			preWord=commands.get(containerDex-1);

		int maxContained=Integer.MAX_VALUE;
		if(CMath.s_int(preWord)>0)
		{
			maxContained=CMath.s_int(preWord);
			commands.set(containerDex-1,"all");
			containerDex--;
			preWord="all";
		}

		if (preWord.equalsIgnoreCase("all"))
		{
			allFlag = true;
			possibleContainerID = "ALL " + possibleContainerID;
		}
		else 
		if (possibleContainerID.toUpperCase().startsWith("ALL."))
		{
			allFlag = true;
			possibleContainerID = "ALL " + possibleContainerID.substring(4);
		}
		else 
		if (possibleContainerID.toUpperCase().endsWith(".ALL"))
		{
			allFlag = true;
			possibleContainerID = "ALL " + possibleContainerID.substring(0, possibleContainerID.length() - 4);
		}

		int addendum=1;
		String addendumStr="";
		boolean doBugFix = true;
		while(doBugFix || ((allFlag)&&(addendum<=maxContained)))
		{
			doBugFix=false;
			final Environmental E=mob.location().fetchFromMOBRoomFavorsItems(mob,null,possibleContainerID+addendumStr,filter);
			if((E!=null)
			&&(E instanceof Item)
			&&(((Item)E) instanceof Container)
			&&((!withContentOnly)||(((Container)E).hasContent()))
			&&(CMLib.flags().canBeSeenBy(E,mob)||mob.isMine(E)))
			{
				V.addElement((Container)E);
				if(V.size()==1)
				{
					while((fromDex>=0)&&(commands.size()>fromDex))
						commands.remove(fromDex);
					while(commands.size()>containerDex)
						commands.remove(containerDex);
					preWord="";
				}
			}
			if(E==null)
				return V;
			addendumStr="."+(++addendum);
		}
		return V;
	}

	@Override
	public Item possibleContainer(MOB mob, List<String> commands, boolean withStuff, Filterer<Environmental> filter)
	{
		if(commands.size()==1)
			return null;

		final Room R=(mob==null)?null:mob.location();
		if(R==null)
			return null;

		int fromDex=-1;
		int containerDex=commands.size()-1;
		for(int i=commands.size()-2;i>=1;i--)
		{
			if(commands.get(i).equalsIgnoreCase("from") || commands.get(i).equalsIgnoreCase("in")|| commands.get(i).equalsIgnoreCase("on"))
			{ 
				fromDex=i; 
				containerDex=i+1;  
				break;
			}
		}
		
		final String possibleContainerID=CMParms.combine(commands,containerDex);

		Environmental E=R.fetchFromMOBRoomFavorsItems(mob,null,possibleContainerID,filter);
		if(E==null)
		{
			final CMFlagLibrary flagLib=CMLib.flags();
			for(int i=0;i<R.numItems();i++)
			{
				final Item I=R.getItem(i);
				if(flagLib.isOpenAccessibleContainer(I))
				{
					E=R.fetchFromMOBRoomFavorsItems(mob,I,possibleContainerID,filter);
					if(E instanceof Container)
						break;
				}
			}
		}
		if((E!=null)
		&&(E instanceof Item)
		&&(((Item)E) instanceof Container)
		&&((!withStuff)||(((Container)E).hasContent())))
		{
			while((fromDex>=0)&&(commands.size()>fromDex))
				commands.remove(fromDex);
			while(commands.size()>containerDex)
				commands.remove(containerDex);
			return (Item)E;
		}
		return null;
	}

	@Override
	public String returnTime(long millis, long ticks)
	{
		String avg="";
		if(ticks>0)
			avg=", Average="+(millis/ticks)+"ms";
		if(millis<1000)
			return millis+"ms"+avg;
		long seconds=millis/1000;
		millis-=(seconds*1000);
		if(seconds<60)
			return seconds+"s "+millis+"ms"+avg;
		long minutes=seconds/60;
		seconds-=(minutes*60);
		if(minutes<60)
			return minutes+"m "+seconds+"s "+millis+"ms"+avg;
		long hours=minutes/60;
		minutes-=(hours*60);
		if(hours<24)
			return hours+"h "+minutes+"m "+seconds+"s "+millis+"ms"+avg;
		final long days=hours/24;
		hours-=(days*24);
		return days+"d "+hours+"h "+minutes+"m "+seconds+"s "+millis+"ms"+avg;
	}

	@Override
	public Object[] parseMoneyStringSDL(MOB mob, String amount, String correctCurrency)
	{
		double b=0;
		String myCurrency=CMLib.beanCounter().getCurrency(mob);
		double denomination=1.0;
		if(correctCurrency==null)
			correctCurrency=myCurrency;
		if(amount.length()>0)
		{
			myCurrency=CMLib.english().numPossibleGoldCurrency(mob,amount);
			if(myCurrency!=null)
			{
				denomination=CMLib.english().numPossibleGoldDenomination(null,correctCurrency,amount);
				final long num=CMLib.english().numPossibleGold(null,amount);
				b=CMath.mul(denomination,num);
			}
			else
				myCurrency=CMLib.beanCounter().getCurrency(mob);
		}
		return new Object[]{myCurrency,Double.valueOf(denomination),Long.valueOf(Math.round(b/denomination))};
	}

	@Override
	public int calculateMaxToGive(MOB mob, List<String> commands, boolean breakPackages, Environmental checkWhat, boolean getOnly)
	{
		int maxToGive=Integer.MAX_VALUE;
		if((commands.size()>1)
		&&(CMLib.english().numPossibleGold(mob,CMParms.combine(commands,0))==0))
		{
			if(CMath.s_int(commands.get(0))>0)
			{
				maxToGive=CMath.s_int(commands.get(0));
				commands.set(0,"all");
				if(breakPackages)
				{
					boolean throwError=false;
					if((commands.size()>2)&&("FROM".startsWith(commands.get(1).toUpperCase())))
					{
						throwError=true;
						commands.remove(1);
					}
					final String packCheckName=CMParms.combine(commands,1);
					Environmental fromWhat=null;
					if(checkWhat instanceof MOB)
						fromWhat=mob.findItem(null,packCheckName);
					else
					if(checkWhat instanceof Room)
						fromWhat=((Room)checkWhat).fetchFromMOBRoomFavorsItems(mob,null,packCheckName,Wearable.FILTER_UNWORNONLY);
					if(fromWhat instanceof Item)
					{
						int max=mob.maxCarry();
						if(max>3000)
							max=3000;
						if(maxToGive>max)
						{
							CMLib.commands().doCommandFail(mob,new XVector<String>(commands),L("You can only handle @x1 at a time.",""+max));
							return -1;
						}
						final Environmental toWhat=CMLib.materials().unbundle((Item)fromWhat,maxToGive,null);
						if(toWhat==null)
						{
							if(throwError)
							{
								CMLib.commands().doCommandFail(mob,new XVector<String>(commands),L("You can't get anything from @x1.",fromWhat.name()));
								return -1;
							}
						}
						else
						if(getOnly&&mob.isMine(fromWhat)&&mob.isMine(toWhat))
						{
							mob.tell(L("Ok"));
							return -1;
						}
						else
						if(commands.size()==1)
							commands.add(toWhat.name());
						else
						{
							final String O=commands.get(0);
							commands.clear();
							commands.add(O);
							commands.add(toWhat.name());
						}
					}
					else
					if(throwError)
					{
						CMLib.commands().doCommandFail(mob,new XVector<String>(commands),L("You don't see '@x1' here.",packCheckName));
						return -1;
					}
				}
			}
			else
			if(!CMath.isInteger(commands.get(0)))
			{
				int x = CMParms.indexOfIgnoreCase(commands,"FROM");
				if((x>0)&&(x<commands.size()-1))
				{
					final String packCheckName=CMParms.combine(commands,x+1);
					final String getName = CMParms.combine(commands,0,x);
					Environmental fromWhat=null;
					if(checkWhat instanceof MOB)
						fromWhat=mob.findItem(null,packCheckName);
					else
					if(checkWhat instanceof Room)
						fromWhat=((Room)checkWhat).fetchFromMOBRoomFavorsItems(mob,null,packCheckName,Wearable.FILTER_UNWORNONLY);
					if(fromWhat instanceof Item)
					{
						final Environmental toWhat=CMLib.materials().unbundle((Item)fromWhat,1,null);
						if((toWhat==null)
						||((!CMLib.english().containsString(toWhat.name(), getName))
							&&(!CMLib.english().containsString(toWhat.displayText(), getName))))
						{
							return maxToGive;
						}
						else
						if(getOnly&&mob.isMine(fromWhat)&&mob.isMine(toWhat))
						{
							mob.tell(L("Ok"));
							return -1;
						}
						else
						{
							maxToGive = 1;
							commands.clear();
							commands.add(toWhat.name());
						}
					}
				}
			}
		}
		return maxToGive;
	}

	protected static class FetchFlags
	{
		public String	srchStr;
		public int		occurrance;
		public boolean	allFlag;

		public FetchFlags(String ss, int oc, boolean af)
		{
			srchStr = ss;
			occurrance = oc;
			allFlag = af;
		}
	}

	public FetchFlags fetchFlags(String srchStr)
	{
		if(srchStr.length()==0)
			return null;
		srchStr=srchStr.toUpperCase();
		if((srchStr.length()<2)||(srchStr.equals("THE")))
			return null;

		boolean allFlag=false;
		if(srchStr.startsWith("ALL "))
		{
			srchStr=srchStr.substring(4);
			allFlag=true;
		}
		else
		if(srchStr.equals("ALL"))
			allFlag=true;

		int dot=srchStr.lastIndexOf('.');
		int occurrance=0;
		if(dot>0)
		{
			String sub=srchStr.substring(dot+1);
			occurrance=CMath.s_int(sub);
			if(occurrance>0)
				srchStr=srchStr.substring(0,dot);
			else
			{
				dot=srchStr.indexOf('.');
				sub=srchStr.substring(0,dot);
				occurrance=CMath.s_int(sub);
				if(occurrance>0)
					srchStr=srchStr.substring(dot+1);
				else
					occurrance=0;
			}
		}
		return new FetchFlags(srchStr,occurrance,allFlag);
	}

	protected String cleanExtraneousDollarMarkers(String srchStr)
	{
		if(srchStr.startsWith("$"))
		{
			if(srchStr.endsWith("$")&&(srchStr.length()>1))
				return srchStr.substring(1,srchStr.length()-1);
			else
				return srchStr.substring(1);
		}
		else
		if(srchStr.endsWith("$"))
			return srchStr.substring(0,srchStr.length()-1);
		return srchStr;
	}

	@Override
	public Environmental fetchEnvironmental(Iterable<? extends Environmental> list, String srchStr, boolean exactOnly)
	{
		final FetchFlags flags=fetchFlags(srchStr);
		if(flags==null)
			return null;

		srchStr=flags.srchStr;
		int myOccurrance=flags.occurrance;
		final boolean allFlag=flags.allFlag;
		try
		{
			if(exactOnly)
			{
				srchStr=cleanExtraneousDollarMarkers(srchStr);
				for (final Environmental E : list)
				{
					if(E!=null)
					{
						if(E.ID().equalsIgnoreCase(srchStr)
						||E.name().equalsIgnoreCase(srchStr)
						||E.Name().equalsIgnoreCase(srchStr))
						{
							if((!allFlag)||(E instanceof Ability)||((E.displayText()!=null)&&(E.displayText().length()>0)))
							{
								if((--myOccurrance)<=0)
									return E;
							}
						}
					}
				}
			}
			else
			{
				myOccurrance=flags.occurrance;
				for (final Environmental E : list)
				{
					if((E!=null)
					&&(containsString(E.name(),srchStr)||containsString(E.Name(),srchStr))
					&&((!allFlag)||(E instanceof Ability)||((E.displayText()!=null)&&(E.displayText().length()>0))))
					{
						if((--myOccurrance)<=0)
							return E;
					}
				}
				myOccurrance=flags.occurrance;
				for (final Environmental E : list)
				{
					if((E!=null)
					&&(!(E instanceof Ability))
					&&(containsString(E.displayText(),srchStr)
						||((E instanceof MOB)&&containsString(((MOB)E).genericName(),srchStr))))
					{
						if((--myOccurrance)<=0)
							return E;
					}
				}
			}
		}
		catch (final java.lang.ArrayIndexOutOfBoundsException x)
		{
		}
		return null;
	}

	@Override
	public Exit fetchExit(Iterable<? extends Environmental> list, String srchStr, boolean exactOnly)
	{
		final FetchFlags flags=fetchFlags(srchStr);
		if(flags==null)
			return null;

		srchStr=flags.srchStr;
		int myOccurrance=flags.occurrance;
		final boolean allFlag=flags.allFlag;
		try
		{
			if(exactOnly)
			{
				srchStr=cleanExtraneousDollarMarkers(srchStr);
				for (final Environmental E : list)
				{
					if(E instanceof Exit)
					{
						if(E.ID().equalsIgnoreCase(srchStr)
						||E.name().equalsIgnoreCase(srchStr)
						||E.Name().equalsIgnoreCase(srchStr)
						||((Exit)E).doorName().equalsIgnoreCase(srchStr)
						||((Exit)E).closedText().equalsIgnoreCase(srchStr))
						{
							if((!allFlag)||((E.displayText()!=null)&&(E.displayText().length()>0)))
							{
								if((--myOccurrance)<=0)
									return (Exit)E;
							}
						}
					}
				}
			}
			else
			{
				myOccurrance=flags.occurrance;
				for (final Environmental E : list)
				{
					if((E instanceof Exit)
					&&(containsString(E.name(),srchStr)
						||containsString(E.Name(),srchStr)
						||containsString(((Exit)E).doorName(),srchStr)
						||containsString(((Exit)E).closedText(),srchStr))
					&&((!allFlag)||((E.displayText()!=null)&&(E.displayText().length()>0))))
					{
						if((--myOccurrance)<=0)
							return (Exit)E;
					}
				}
				myOccurrance=flags.occurrance;
				for (final Environmental E : list)
				{
					if((E instanceof Exit)
					&&(containsString(E.displayText(),srchStr)))
					{
						if((--myOccurrance)<=0)
							return (Exit)E;
					}
				}
			}
		}
		catch (final java.lang.ArrayIndexOutOfBoundsException x)
		{
		}
		return null;
	}

	@Override
	public Environmental fetchEnvironmental(Iterator<? extends Environmental> iter, String srchStr, boolean exactOnly)
	{
		final FetchFlags flags=fetchFlags(srchStr);
		if(flags==null)
			return null;

		srchStr=flags.srchStr;
		int myOccurrance=flags.occurrance;
		final boolean allFlag=flags.allFlag;
		try
		{
			if(exactOnly)
			{
				srchStr=cleanExtraneousDollarMarkers(srchStr);
				for (;iter.hasNext();)
				{
					final Environmental E=iter.next();
					if(E!=null)
					{
						if(E.ID().equalsIgnoreCase(srchStr)
						||E.name().equalsIgnoreCase(srchStr)
						||E.Name().equalsIgnoreCase(srchStr))
						{
							if((!allFlag)||(E instanceof Ability)||((E.displayText()!=null)&&(E.displayText().length()>0)))
							{
								if((--myOccurrance)<=0)
									return E;
							}
						}
					}
				}
			}
			else
			{
				myOccurrance=flags.occurrance;
				for (;iter.hasNext();)
				{
					final Environmental E=iter.next();
					if((E!=null)
					&&(containsString(E.name(),srchStr)
						||containsString(E.Name(),srchStr)
						||containsString(E.displayText(),srchStr)
						||((E instanceof MOB)&&containsString(((MOB)E).genericName(),srchStr)))
					&&((!allFlag)||(E instanceof Ability)||((E.displayText()!=null)&&(E.displayText().length()>0))))
					{
						if((--myOccurrance)<=0)
							return E;
					}
				}
			}
		}
		catch (final java.lang.ArrayIndexOutOfBoundsException x)
		{
		}
		return null;
	}

	@Override
	public Environmental fetchEnvironmental(Enumeration<? extends Environmental> iter, String srchStr, boolean exactOnly)
	{
		final FetchFlags flags=fetchFlags(srchStr);
		if(flags==null)
			return null;

		srchStr=flags.srchStr;
		int myOccurrance=flags.occurrance;
		final boolean allFlag=flags.allFlag;
		try
		{
			if(exactOnly)
			{
				srchStr=cleanExtraneousDollarMarkers(srchStr);
				for (;iter.hasMoreElements();)
				{
					final Environmental E=iter.nextElement();
					if(E!=null)
					{
						if(E.ID().equalsIgnoreCase(srchStr)
						||E.name().equalsIgnoreCase(srchStr)
						||E.Name().equalsIgnoreCase(srchStr))
						{
							if((!allFlag)||(E instanceof Ability)||((E.displayText()!=null)&&(E.displayText().length()>0)))
							{
								if((--myOccurrance)<=0)
									return E;
							}
						}
					}
				}
			}
			else
			{
				myOccurrance=flags.occurrance;
				for (;iter.hasMoreElements();)
				{
					final Environmental E=iter.nextElement();
					if((E!=null)
					&&(containsString(E.name(),srchStr)
						||containsString(E.Name(),srchStr)
						||containsString(E.displayText(),srchStr)
						||((E instanceof MOB)&&containsString(((MOB)E).genericName(),srchStr)))
					&&((!allFlag)||(E instanceof Ability)||((E.displayText()!=null)&&(E.displayText().length()>0))))
					{
						if((--myOccurrance)<=0)
							return E;
					}
				}
			}
		}
		catch (final java.lang.ArrayIndexOutOfBoundsException x)
		{
		}
		return null;
	}

	@Override
	public List<Environmental> fetchEnvironmentals(List<? extends Environmental> list, String srchStr, boolean exactOnly)
	{
		final Vector<Environmental> matches=new Vector<Environmental>(1);
		if(list.isEmpty())
			return matches;
		final FetchFlags flags=fetchFlags(srchStr);
		if(flags==null)
			return matches;

		srchStr=flags.srchStr;
		int myOccurrance=flags.occurrance;
		final boolean allFlag=flags.allFlag;
		try
		{
			if(exactOnly)
			{
				srchStr=cleanExtraneousDollarMarkers(srchStr);
				for (final Environmental E : list)
				{
					if(E!=null)
					{
						if(E.ID().equalsIgnoreCase(srchStr)
						||E.name().equalsIgnoreCase(srchStr)
						||E.Name().equalsIgnoreCase(srchStr))
						{
							if((!allFlag)||(E instanceof Ability)||((E.displayText()!=null)&&(E.displayText().length()>0)))
							{
								if((--myOccurrance)<=0)
									matches.addElement(E);
							}
						}
					}
				}
			}
			else
			{
				myOccurrance=flags.occurrance;
				for (final Environmental E : list)
				{
					if((E!=null)
					&&(containsString(E.name(),srchStr)||containsString(E.Name(),srchStr))
					&&((!allFlag)||(E instanceof Ability)||((E.displayText()!=null)&&(E.displayText().length()>0))))
					{
						if((--myOccurrance)<=0)
							matches.addElement(E);
					}
				}
				if(matches.isEmpty())
				{
					myOccurrance=flags.occurrance;
					for (final Environmental E : list)
					{
						if((E!=null)
						&&(!(E instanceof Ability))
						&&(containsString(E.displayText(),srchStr)
							||((E instanceof MOB)&&containsString(((MOB)E).genericName(),srchStr))))
						{
							if((--myOccurrance)<=0)
								matches.addElement(E);
						}
					}
				}
			}
		}
		catch (final java.lang.ArrayIndexOutOfBoundsException x)
		{
		}
		return matches;
	}

	@Override
	public Environmental fetchEnvironmental(Map<String, ? extends Environmental> list, String srchStr, boolean exactOnly)
	{
		if(list.isEmpty())
			return null;
		final FetchFlags flags=fetchFlags(srchStr);
		if(flags==null)
			return null;

		srchStr=flags.srchStr;
		int myOccurrance=flags.occurrance;
		final boolean allFlag=flags.allFlag;

		if(list.get(srchStr)!=null)
			return list.get(srchStr);
		Environmental E=null;
		if(exactOnly)
		{
			srchStr=cleanExtraneousDollarMarkers(srchStr);
			for (final String string : list.keySet())
			{
				E=list.get(string);
				if(E!=null)
				{
					if(E.ID().equalsIgnoreCase(srchStr)
					||E.Name().equalsIgnoreCase(srchStr)
					||E.name().equalsIgnoreCase(srchStr))
					{
						if((!allFlag)||(E instanceof Ability)||((E.displayText()!=null)&&(E.displayText().length()>0)))
						{
							if((--myOccurrance)<=0)
								return E;
						}
					}
				}
			}
		}
		else
		{
			myOccurrance=flags.occurrance;
			for (final String string : list.keySet())
			{
				E=list.get(string);
				if((E!=null)
				&&(containsString(E.name(),srchStr)||containsString(E.Name(),srchStr))
				&&((!allFlag)||(E instanceof Ability)||((E.displayText()!=null)&&(E.displayText().length()>0))))
				{
					if((--myOccurrance)<=0)
						return E;
				}
			}
			myOccurrance=flags.occurrance;
			for (final String string : list.keySet())
			{
				E=list.get(string);
				if(E!=null)
				{
					if((containsString(E.displayText(),srchStr))
					||((E instanceof MOB) && containsString(((MOB)E).genericName(),srchStr)))
					{
						if((--myOccurrance)<=0)
							return E;
					}
				}
			}
		}
		return null;
	}

	@Override
	public Item fetchAvailableItem(List<Item> list, String srchStr, Item goodLocation, Filterer<Environmental> filter, boolean exactOnly)
	{
		if(list.isEmpty())
			return null;
		final FetchFlags flags=fetchFlags(srchStr);
		if(flags==null)
			return null;

		srchStr=flags.srchStr;
		int myOccurrance=flags.occurrance;
		final boolean allFlag=flags.allFlag;
		if(exactOnly)
		{
			try
			{
				srchStr=cleanExtraneousDollarMarkers(srchStr);
				for (final Item I : list)
				{
					if(I==null)
						continue;
					if((I.container()==goodLocation)
					&&(filter.passesFilter(I))
					&&(I.ID().equalsIgnoreCase(srchStr)
					  ||(I.Name().equalsIgnoreCase(srchStr))
					  ||(I.name().equalsIgnoreCase(srchStr))))
					{
						if((!allFlag)||((I.displayText()!=null)&&(I.displayText().length()>0)))
						{
							if((--myOccurrance)<=0)
								return I;
						}
					}
				}
			}
			catch (final java.lang.ArrayIndexOutOfBoundsException x)
			{
			}
		}
		else
		{
			try
			{
				for (final Item I : list)
				{
					if((I!=null)
					&&(I.container()==goodLocation)
					&&(filter.passesFilter(I))
					&&(containsString(I.name(),srchStr)||containsString(I.Name(),srchStr))
					&&((!allFlag)||((I.displayText()!=null)&&(I.displayText().length()>0))))
					{
						if((--myOccurrance)<=0)
							return I;
					}
				}
			}
			catch (final java.lang.ArrayIndexOutOfBoundsException x)
			{
			}
			myOccurrance=flags.occurrance;
			try
			{
				for (final Item I : list)
				{
					if((I!=null)
					&&(I.container()==goodLocation)
					&&(filter.passesFilter(I))
					&&(containsString(I.displayText(),srchStr)))
					{
						if((--myOccurrance)<=0)
							return I;
					}
				}
			}
			catch (final java.lang.ArrayIndexOutOfBoundsException x)
			{
			}
		}
		return null;
	}

	@Override
	public List<Item> fetchAvailableItems(List<Item> list, String srchStr, Item goodLocation, Filterer<Environmental> filter, boolean exactOnly)
	{
		final Vector<Item> matches=new Vector<Item>(1);
		if(list.isEmpty())
			return matches;
		final FetchFlags flags=fetchFlags(srchStr);
		if(flags==null)
			return matches;

		srchStr=flags.srchStr;
		int myOccurrance=flags.occurrance;
		final boolean allFlag=flags.allFlag;
		try
		{
			if(exactOnly)
			{
				srchStr=cleanExtraneousDollarMarkers(srchStr);
				for (final Item I : list)
				{
					if(I==null)
						continue;
					if((I.container()==goodLocation)
					&&(filter.passesFilter(I))
					&&(I.ID().equalsIgnoreCase(srchStr)
					   ||(I.Name().equalsIgnoreCase(srchStr))
					   ||(I.name().equalsIgnoreCase(srchStr))))
					{
						if((!allFlag)||((I.displayText()!=null)&&(I.displayText().length()>0)))
						{
							if((--myOccurrance)<=0)
								matches.addElement(I);
						}
					}
				}
			}
			else
			{
				for (final Item I : list)
				{
					if(I==null)
						continue;
					if((I.container()==goodLocation)
					&&(filter.passesFilter(I))
					&&(containsString(I.name(),srchStr)||containsString(I.Name(),srchStr))
					&&((!allFlag)||((I.displayText()!=null)&&(I.displayText().length()>0))))
					{
						if((--myOccurrance)<=0)
							matches.addElement(I);
					}
				}
				if(matches.isEmpty())
				{
					myOccurrance=flags.occurrance;
					for (final Item I : list)
					{
						if(I==null)
							continue;
						if((I.container()==goodLocation)
						&&(filter.passesFilter(I))
						&&(containsString(I.displayText(),srchStr)))
						{
							if((--myOccurrance)<=0)
								matches.addElement(I);
						}
					}
				}
			}
		}
		catch (final java.lang.ArrayIndexOutOfBoundsException x)
		{
		}
		return matches;
	}

	@Override
	public Environmental fetchAvailable(Collection<? extends Environmental> list, String srchStr, Item goodLocation, Filterer<Environmental> filter, boolean exactOnly, int[] counterSlap)
	{
		if(list.isEmpty())
			return null;
		final FetchFlags flags=fetchFlags(srchStr);
		if(flags==null)
			return null;

		srchStr=flags.srchStr;
		int myOccurrance=flags.occurrance - counterSlap[0];
		final boolean allFlag=flags.allFlag;

		Item I=null;
		try
		{
			if(exactOnly)
			{
				srchStr=cleanExtraneousDollarMarkers(srchStr);
				for (final Environmental E : list)
				{
					if(E instanceof Item)
					{
						I=(Item)E;
						if((I.container()==goodLocation)
						&&(filter.passesFilter(I))
						&&(I.ID().equalsIgnoreCase(srchStr)
						   ||(I.Name().equalsIgnoreCase(srchStr))
						   ||(I.name().equalsIgnoreCase(srchStr))))
						{
							if((!allFlag)||(E instanceof Ability)||((I.displayText()!=null)&&(I.displayText().length()>0)))
							{
								if((--myOccurrance)<=0)
									return I;
							}
						}
					}
					else
					if(E!=null)
					{
						if(E.ID().equalsIgnoreCase(srchStr)
						||E.Name().equalsIgnoreCase(srchStr)
						||E.name().equalsIgnoreCase(srchStr))
						{
							if((!allFlag)||(E instanceof Ability)||((E.displayText()!=null)&&(E.displayText().length()>0)))
							{
								if((--myOccurrance)<=0)
									return E;
							}
						}
					}
				}
			}
			else
			{
				for (final Environmental E : list)
				{
					if(E instanceof Item)
					{
						I=(Item)E;
						if((I.container()==goodLocation)
						&&(filter.passesFilter(I))
						&&(containsString(I.name(),srchStr)||containsString(I.Name(),srchStr))
						&&((!allFlag)||(E instanceof Ability)||((I.displayText()!=null)&&(I.displayText().length()>0))))
						{
							if((--myOccurrance)<=0)
								return I;
						}
					}
					else
					if((E!=null)
					&&(containsString(E.name(),srchStr)||containsString(E.Name(),srchStr))
					&&((!allFlag)||(E instanceof Ability)||((E.displayText()!=null)&&(E.displayText().length()>0))))
					{
						if((--myOccurrance)<=0)
							return E;
					}
				}

				myOccurrance=flags.occurrance - counterSlap[0];
				for (final Environmental E : list)
				{
					if(E instanceof Item)
					{
						I=(Item)E;
						if((I.container()==goodLocation)
						&&(filter.passesFilter(I))
						&&(containsString(I.displayText(),srchStr)))
						{
							if((--myOccurrance)<=0)
								return I;
						}
					}
					else
					if(E!=null)
					{
						if((containsString(E.displayText(),srchStr))
						||((E instanceof MOB)&&containsString(((MOB)E).genericName(),srchStr)))
						{
							if((--myOccurrance)<=0)
								return E;
						}
					}
				}
			}
		}
		catch (final java.lang.ArrayIndexOutOfBoundsException x)
		{
		}
		counterSlap[0]+=(flags.occurrance-myOccurrance);
		return null;
	}
	
	@Override
	public Environmental fetchAvailable(Collection<? extends Environmental> list, String srchStr, Item goodLocation, Filterer<Environmental> filter, boolean exactOnly)
	{
		if(list.isEmpty())
			return null;
		final FetchFlags flags=fetchFlags(srchStr);
		if(flags==null)
			return null;

		srchStr=flags.srchStr;
		int myOccurrance=flags.occurrance;
		final boolean allFlag=flags.allFlag;

		Item I=null;
		try
		{
			if(exactOnly)
			{
				srchStr=cleanExtraneousDollarMarkers(srchStr);
				for (final Environmental E : list)
				{
					if(E instanceof Item)
					{
						I=(Item)E;
						if((I.container()==goodLocation)
						&&(filter.passesFilter(I))
						&&(I.ID().equalsIgnoreCase(srchStr)
						   ||(I.Name().equalsIgnoreCase(srchStr))
						   ||(I.name().equalsIgnoreCase(srchStr))))
						{
							if((!allFlag)||(E instanceof Ability)||((I.displayText()!=null)&&(I.displayText().length()>0)))
							{
								if((--myOccurrance)<=0)
									return I;
							}
						}
					}
					else
					if(E!=null)
					{
						if(E.ID().equalsIgnoreCase(srchStr)
						||E.Name().equalsIgnoreCase(srchStr)
						||E.name().equalsIgnoreCase(srchStr))
						{
							if((!allFlag)||(E instanceof Ability)||((E.displayText()!=null)&&(E.displayText().length()>0)))
							{
								if((--myOccurrance)<=0)
									return E;
							}
						}
					}
				}
			}
			else
			{
				for (final Environmental E : list)
				{
					if(E instanceof Item)
					{
						I=(Item)E;
						if((I.container()==goodLocation)
						&&(filter.passesFilter(I))
						&&(containsString(I.name(),srchStr)||containsString(I.Name(),srchStr))
						&&((!allFlag)||(E instanceof Ability)||((I.displayText()!=null)&&(I.displayText().length()>0))))
						{
							if((--myOccurrance)<=0)
								return I;
						}
					}
					else
					if((E!=null)
					&&(containsString(E.name(),srchStr)||containsString(E.Name(),srchStr))
					&&((!allFlag)||(E instanceof Ability)||((E.displayText()!=null)&&(E.displayText().length()>0))))
					{
						if((--myOccurrance)<=0)
							return E;
					}
				}

				myOccurrance=flags.occurrance;
				for (final Environmental E : list)
				{
					if(E instanceof Item)
					{
						I=(Item)E;
						if((I.container()==goodLocation)
						&&(filter.passesFilter(I))
						&&(containsString(I.displayText(),srchStr)))
						{
							if((--myOccurrance)<=0)
								return I;
						}
					}
					else
					if(E!=null)
					{
						if((containsString(E.displayText(),srchStr))
						||((E instanceof MOB)&&containsString(((MOB)E).genericName(),srchStr)))
						{
							if((--myOccurrance)<=0)
								return E;
						}
					}
				}
			}
		}
		catch (final java.lang.ArrayIndexOutOfBoundsException x)
		{
		}
		return null;
	}
}