protected void mapAbilityFinal(String abilityID, Map<String, AbilityMapping> ableMap, AbilityMapping able)
	{
		if(CMSecurity.isAbilityDisabled(able.abilityID().toUpperCase()))
			return;
		ableMap.put(abilityID,able);
		
		final boolean isACharacterClass = CMClass.getCharClass(able.ID()) != null || (able.ID().equalsIgnoreCase("All"));

		final int qualLevel = able.qualLevel();
		final int maxProficiency = able.maxProficiency();

		if(isACharacterClass)
		{
			// set lowest level map
			final Integer lowLevel=lowestQualifyingLevelMap.get(abilityID);
			if(qualLevel > 0)
			{
				if((lowLevel==null)
				||(qualLevel<lowLevel.intValue()))
					lowestQualifyingLevelMap.put(abilityID,Integer.valueOf(qualLevel));
			}

			// and max proficiency maps
			final Integer maxProf=maxProficiencyMap.get(abilityID);
			if((maxProf==null)
			||(maxProficiency>maxProf.intValue()))
				maxProficiencyMap.put(abilityID,Integer.valueOf(maxProficiency));
		}

		// and the reverse lookup map
		Map<String, AbilityMapping> revT = reverseAbilityMap.get(abilityID);
		if(revT==null)
		{
			revT = new TreeMap<String, AbilityMapping>();
			reverseAbilityMap.put(abilityID,revT);
		}
		if(!revT.containsKey(able.ID()))
			revT.put(able.ID(), able);

		// archons get everything
		if(isACharacterClass)
		{
			final int arc_level=getQualifyingLevel("Archon",true,abilityID);
			if(((arc_level<0)||((qualLevel>=0)&&(qualLevel<arc_level)))
			&&(!able.ID().equalsIgnoreCase("Archon"))
			&&(!able.ID().equalsIgnoreCase("All")))
			{
				addCharAbilityMapping("Archon",qualLevel,abilityID,true);
			}
		}
	}