protected Race buildGenRace(Modifiable E, XMLTag piece, Map<String,Object> defined) throws CMException
	{
		final String classID = findStringNow("class",piece,defined);
		Race R=CMClass.getRace(classID);
		if( R != null)
			return R;
		R=(Race)CMClass.getRace("GenRace").copyOf();
		int numStatsFound=0;
		for(String stat : R.getStatCodes())
			try
			{
				if(findOptionalString(null, null, null, stat, piece, defined, false)!=null)
					numStatsFound++;
			}
			catch(PostProcessException pe)
			{
				numStatsFound++;
			}
		if(numStatsFound<5)
			throw new CMException("Too few fields to build race on classID '"+classID+"', Data: "+CMParms.toKeyValueSlashListString(piece.parms())+":"+CMStrings.limit(piece.value(),100));
		R.setRacialParms("<RACE><ID>"+CMStrings.capitalizeAndLower(classID)+"</ID><NAME>"+CMStrings.capitalizeAndLower(classID)+"</NAME></RACE>");
		CMClass.addRace(R);
		addDefinition("RACE_CLASS",R.ID(),defined); // define so we can mess with it
		R.setStat("NAME", findStringNow("name",piece,defined));
		addDefinition("RACE_NAME",R.name(),defined); // define so we can mess with it
		final List<String> ignoreStats=new XVector<String>(new String[]{"CLASS","NAME"});
		
		final List<Item> raceWeapons=getRaceItems(E,"WEAPON","RACE_WEAPON_",piece,defined);
		if(raceWeapons.size()>0)
		{
			Item I=raceWeapons.get(CMLib.dice().roll(1, raceWeapons.size(), -1));
			R.setStat("WEAPONCLASS", I.ID());
			R.setStat("WEAPONXML", I.text());
		}
		ignoreStats.addAll(Arrays.asList(new String[]{"WEAPONCLASS","WEAPONXML"}));
		
		final List<Item> raceResources=getRaceItems(E,"RESOURCES","RACE_RESOURCE_",piece,defined);
		R.setStat("NUMRSC", ""+raceResources.size());
		for(int i=0;i<raceResources.size();i++)
		{
			final Item I=raceResources.get(i);
			R.setStat("GETRSCID"+i, I.ID());
			R.setStat("GETRSCPARM"+i, ""+I.text());
		}
		ignoreStats.addAll(Arrays.asList(new String[]{"NUMRSC","GETRSCID","GETRSCPARM"}));
		final List<Item> raceOutfit=getRaceItems(E,"OUTFIT","RACE_RESOURCE_",piece,defined);
		R.setStat("NUMOFT", ""+raceOutfit.size());
		for(int i=0;i<raceOutfit.size();i++)
		{
			final Item I=raceOutfit.get(i);
			R.setStat("GETOFTID"+i, I.ID());
			R.setStat("GETOFTPARM"+i, ""+I.text());
		}
		ignoreStats.addAll(Arrays.asList(new String[]{"NUMOFT","GETOFTID","GETOFTPARM"}));
		final List<AbilityMapping> rables = findRaceAbles(E,"ABILITY","RACE_ABLE_",piece,defined);
		R.setStat("NUMRABLE", ""+rables.size());
		for(int i=0;i<rables.size();i++)
		{
			final AbilityMapping ableMap=rables.get(i);
			R.setStat("GETRABLE"+i, ableMap.abilityID());
			R.setStat("GETRABLEPROF"+i, ""+ableMap.defaultProficiency());
			R.setStat("GETRABLEQUAL"+i, ""+(!ableMap.autoGain()));
			R.setStat("GETRABLELVL"+i, ""+ableMap.qualLevel());
			R.setStat("GETRABLEPARM"+i, ableMap.defaultParm());
		}
		ignoreStats.addAll(Arrays.asList(new String[]{"NUMRABLE","GETRABLE","GETRABLEPROF","GETRABLEQUAL","GETRABLELVL","GETRABLEPARM"}));
		final List<AbilityMapping> cables = findRaceAbles(E,"CULTUREABILITY","RACE_CULT_ABLE_",piece,defined);
		R.setStat("NUMCABLE", ""+cables.size());
		for(int i=0;i<cables.size();i++)
		{
			final AbilityMapping ableMap=cables.get(i);
			R.setStat("GETCABLE"+i, ableMap.abilityID());
			R.setStat("GETCABLEPROF"+i, ""+ableMap.defaultProficiency());
		}
		ignoreStats.addAll(Arrays.asList(new String[]{"NUMCABLE","GETCABLE","GETCABLEPROF"}));
		final List<AbilityMapping> reffs = findRaceAbles(E,"AFFECT","RACE_EFFECT_",piece,defined);
		R.setStat("NUMREFF", ""+reffs.size());
		for(int i=0;i<reffs.size();i++)
		{
			final AbilityMapping ableMap=reffs.get(i);
			R.setStat("GETREFF"+i, ableMap.abilityID());
			R.setStat("GETREFFPARM"+i, ""+ableMap.defaultParm());
			R.setStat("GETREFFLVL"+i, ""+ableMap.qualLevel());
		}
		ignoreStats.addAll(Arrays.asList(new String[]{"NUMREFF","GETREFF","GETREFFPARM","GETREFFLVL"}));
		
		final List<AbilityMapping> iables = findRaceAbles(E,"IMMUNITY","RACE_IMMUNITY_",piece,defined);
		R.setStat("NUMIABLE", ""+reffs.size());
		for(int i=0;i<iables.size();i++)
		{
			final AbilityMapping ableMap=reffs.get(i);
			R.setStat("GETIABLE"+i, ableMap.abilityID());
		}
		ignoreStats.addAll(Arrays.asList(new String[]{"NUMIABLE","GETIABLE"}));
		
		fillOutStatCodes(R,ignoreStats,"RACE_",piece,defined);
		CMLib.database().DBCreateRace(R.ID(),R.racialParms());
		return R;
	}