protected List<Item> buildItem(XMLTag piece, Map<String,Object> defined) throws CMException
	{
		final String classID = findStringNow("class",piece,defined);
		final List<Item> contents = new Vector<Item>();
		final List<String> ignoreStats=new XVector<String>();
		if(classID.toLowerCase().startsWith("metacraft"))
		{
			final String classRest=classID.substring(9).toLowerCase().trim();
			final Triad<Integer,Integer,Class<?>[]> filter = new Triad<Integer,Integer,Class<?>[]>(Integer.valueOf(-1),Integer.valueOf(-1),new Class<?>[0]);
			String recipe="anything";
			if(classRest.startsWith(":"))
			{
				recipe=getMetacraftFilter(classRest.substring(1).trim(), piece, defined, filter);
			}
			else
			{
				recipe = findStringNow("NAME",piece,defined);
				if((recipe == null)||(recipe.length()==0))
					throw new CMException("Unable to metacraft with malformed class Data: "+CMParms.toKeyValueSlashListString(piece.parms())+":"+CMStrings.limit(piece.value(),100));
			}

			final String materialStr = findOptionalStringNow(null,null,null,"material",piece,defined, false);
			int material=-1;
			if(materialStr!=null)
				 material = RawMaterial.CODES.FIND_IgnoreCase(materialStr);
			final List<ItemCraftor> craftors=new Vector<ItemCraftor>();
			for(final Enumeration<Ability> e=CMClass.abilities();e.hasMoreElements();)
			{
				final Ability A=e.nextElement();
				if(A instanceof ItemCraftor)
					craftors.add((ItemCraftor)A);
			}
			if(recipe.equalsIgnoreCase("anything"))
			{
				final long startTime=System.currentTimeMillis();
				while((contents.size()==0)&&((System.currentTimeMillis()-startTime)<1000))
				{
					final ItemCraftor skill=craftors.get(CMLib.dice().roll(1,craftors.size(),-1));
					if(skill.fetchRecipes().size()>0)
					{
						final List<ItemCraftor.ItemKeyPair> skillContents=craftAllOfThisRecipe(skill,material,defined);
						if(skillContents.size()==0) // preliminary error messaging, just for the craft skills themselves
							Log.errOut("MUDPercolator","Tried metacrafting anything, got "+Integer.toString(skillContents.size())+" from "+skill.ID());
						else
						for(int i=skillContents.size()-1;i>=0;i--)
						{
							final Item I=skillContents.get(i).item;
							if(!checkMetacraftItem(I, filter))
								skillContents.remove(i);
						}
						if(skillContents.size()>0)
							contents.add((Item)skillContents.get(CMLib.dice().roll(1,skillContents.size(),-1)).item.copyOf());
					}
				}
			}
			else
			if(recipe.toLowerCase().startsWith("any-"))
			{
				List<ItemCraftor.ItemKeyPair> skillContents=null;
				recipe=recipe.substring(4).trim();
				for(final ItemCraftor skill : craftors)
				{
					if(skill.ID().equalsIgnoreCase(recipe))
					{
						skillContents=craftAllOfThisRecipe(skill,material,defined);
						if((skillContents==null)||(skillContents.size()==0)) // this is just for checking the skills themselves
							Log.errOut("MUDPercolator","Tried metacrafting any-"+recipe+", got "+Integer.toString(contents.size())+" from "+skill.ID());
						else
						for(int i=skillContents.size()-1;i>=0;i--)
						{
							final Item I=skillContents.get(i).item;
							if(!checkMetacraftItem(I, filter))
								skillContents.remove(i);
						}
						break;
					}
				}
				if((skillContents!=null)&&(skillContents.size()>0))
					contents.add((Item)skillContents.get(CMLib.dice().roll(1,skillContents.size(),-1)).item.copyOf());
			}
			else
			if(recipe.toLowerCase().startsWith("all"))
			{
				List<ItemCraftor.ItemKeyPair> skillContents=null;
				recipe=recipe.substring(3).startsWith("-")?recipe.substring(4).trim():"";
				for(final ItemCraftor skill : craftors)
				{
					if(skill.ID().equalsIgnoreCase(recipe)||(recipe.length()==0))
					{
						skillContents=craftAllOfThisRecipe(skill,material,defined);
						if((skillContents==null)||(skillContents.size()==0)) // this is just for checking the skills themselves
							Log.errOut("MUDPercolator","Tried metacrafting any-"+recipe+", got "+Integer.toString(contents.size())+" from "+skill.ID());
						else
						for(int i=skillContents.size()-1;i>=0;i--)
						{
							final Item I=skillContents.get(i).item;
							if(!checkMetacraftItem(I, filter))
								skillContents.remove(i);
						}
						while((skillContents!=null)&&(skillContents.size()>0))
							contents.add((Item)skillContents.remove(0).item.copyOf());
						if(recipe.length()>0)
							break;
					}
				}
			}
			else
			{
				for(final ItemCraftor skill : craftors)
				{
					final List<List<String>> V=skill.matchingRecipeNames(recipe,false);
					if((V!=null)&&(V.size()>0))
					{
						ItemCraftor.ItemKeyPair pair;
						if(material>=0)
							pair=skill.craftItem(recipe,material,true);
						else
							pair=skill.craftItem(recipe,-1,true);
						if(pair!=null)
						{
							contents.add(pair.item);
							break;
						}
					}
				}
				for(int i=contents.size()-1;i>=0;i--)
				{
					final Item I=contents.get(i);
					if(!checkMetacraftItem(I, filter))
						contents.remove(i);
				}
				if(contents.size()==0)
					for(final ItemCraftor skill : craftors)
					{
						final List<List<String>> V=skill.matchingRecipeNames(recipe,true);
						if((V!=null)&&(V.size()>0))
						{
							ItemCraftor.ItemKeyPair pair;
							if(material>=0)
								pair=skill.craftItem(recipe,material,true);
							else
								pair=skill.craftItem(recipe,0,true);
							if(pair!=null)
							{
								contents.add(pair.item);
								break;
							}
						}
					}
				for(int i=contents.size()-1;i>=0;i--)
				{
					final Item I=contents.get(i);
					if(!checkMetacraftItem(I, filter))
						contents.remove(i);
				}
			}
			if(contents.size()==0)
			{
				if(filter.equals(emptyMetacraftFilter))
					throw new CMException("Unable to metacraft an item called '"+recipe+"', Data: "+CMParms.toKeyValueSlashListString(piece.parms())+":"+CMStrings.limit(piece.value(),100));
				else
					return new ArrayList<Item>(0);
			}
			for(final Item I : contents)
			{
				addDefinition("ITEM_CLASS",I.ID(),defined);
				addDefinition("ITEM_NAME",I.Name(),defined); // define so we can mess with it
				addDefinition("ITEM_LEVEL",""+I.basePhyStats().level(),defined); // define so we can mess with it
				fillOutStatCode(I,ignoreStats,"ITEM_","NAME",piece,defined, false);
				fillOutStatCode(I,ignoreStats,"ITEM_","LEVEL",piece,defined, false);
			}
			ignoreStats.addAll(Arrays.asList(new String[]{"CLASS","MATERIAL","NAME","LEVEL"}));
		}
		else
		if(classID.equalsIgnoreCase("catalog"))
		{
			final String name = findStringNow("NAME",piece,defined);
			if((name == null)||(name.length()==0))
				throw new CMException("Unable to build a catalog item without a name, Data: "+CMParms.toKeyValueSlashListString(piece.parms())+":"+CMStrings.limit(piece.value(),100));
			Item I = CMLib.catalog().getCatalogItem(name);
			if(I==null)
				throw new CMException("Unable to find cataloged item called '"+name+"', Data: "+CMParms.toKeyValueSlashListString(piece.parms())+":"+CMStrings.limit(piece.value(),100));
			I=(Item)I.copyOf();
			CMLib.catalog().changeCatalogUsage(I,true);
			contents.add(I);
			addDefinition("ITEM_CLASS",I.ID(),defined);
			addDefinition("ITEM_NAME",I.Name(),defined); // define so we can mess with it
			ignoreStats.addAll(Arrays.asList(new String[]{"CLASS","NAME"}));
		}
		else
		{
			final Item I = CMClass.getItem(classID);
			if(I == null)
				throw new CMException("Unable to build item on classID '"+classID+"', Data: "+CMParms.toKeyValueSlashListString(piece.parms())+":"+CMStrings.limit(piece.value(),100));
			contents.add(I);
			addDefinition("ITEM_CLASS",classID,defined);

			if(I.isGeneric())
			{
				final boolean filledOut = fillOutCopyCodes(I,ignoreStats,"ITEM_",piece,defined);
				final String name = fillOutStatCode(I,ignoreStats,"ITEM_","NAME",piece,defined, false);
				if((!filledOut) && ((name == null)||(name.length()==0)))
					throw new CMException("Unable to build an item without a name, Data: "+CMParms.toKeyValueSlashListString(piece.parms())+":"+CMStrings.limit(piece.value(),100));
				if((name != null)&&(name.length()>0))
					I.setName(name);
			}
			ignoreStats.addAll(Arrays.asList(new String[]{"CLASS","NAME"}));
			addDefinition("ITEM_NAME",I.Name(),defined); // define so we can mess with it
		}

		final int contentSize=contents.size();
		for(int it=0;it<contentSize;it++) // no iterator, please!!
		{
			final Item I=contents.get(it);
			fillOutStatCodes(I,ignoreStats,"ITEM_",piece,defined);
			I.recoverPhyStats();
			CMLib.itemBuilder().balanceItemByLevel(I);
			I.recoverPhyStats();
			fillOutStatCodes(I,ignoreStats,"ITEM_",piece,defined);
			I.recoverPhyStats();

			if(I instanceof Container)
			{
				final List<Item> V= findContents(piece,defined);
				for(int i=0;i<V.size();i++)
				{
					final Item I2=V.get(i);
					I2.setContainer((Container)I);
					contents.add(I2);
				}
			}
			{
				final List<Ability> V= findAffects(I,piece,defined,null);
				for(int i=0;i<V.size();i++)
				{
					final Ability A=V.get(i);
					A.setSavable(true);
					I.addNonUninvokableEffect(A);
				}
			}
			final List<Behavior> V = findBehaviors(I,piece,defined);
			for(int i=0;i<V.size();i++)
			{
				final Behavior B=V.get(i);
				B.setSavable(true);
				I.addBehavior(B);
			}
			I.recoverPhyStats();
			I.text();
			I.setMiscText(I.text());
			I.recoverPhyStats();
		}
		return contents;
	}