@Override
	public FactionChangeEvent[] findAbilityChangeEvents(Ability key)
	{
		if(key==null) return null;
		// Direct ability ID's
		if(abilityChangesCache.containsKey(key.ID().toUpperCase()))
			return abilityChangesCache.get(key.ID().toUpperCase());
		if(changes.containsKey(key.ID().toUpperCase()))
		{
			abilityChangesCache.put(key.ID().toUpperCase(), abilityChangesCache.get(key.ID().toUpperCase()));
			return abilityChangesCache.get(key.ID().toUpperCase());
		}
		// By TYPE or FLAGS
		FactionChangeEvent[] Cs =null;
		final Vector<FactionChangeEvent> events=new Vector<FactionChangeEvent>();
		for (final Enumeration<FactionChangeEvent[]> e=changes.elements();e.hasMoreElements();)
		{
			Cs=e.nextElement();
			for(final FactionChangeEvent C : Cs)
			{
				if((key.classificationCode()&Ability.ALL_ACODES)==C.IDclassFilter())
					events.addElement(C);
				else
				if((key.classificationCode()&Ability.ALL_DOMAINS)==C.IDdomainFilter())
					events.addElement(C);
				else
				if((C.IDflagFilter()>0)&&(CMath.bset(key.flags(),C.IDflagFilter())))
					events.addElement(C);
			}
		}
		final FactionChangeEvent[] evs = events.toArray(new FactionChangeEvent[0]);
		abilityChangesCache.put(key.ID().toUpperCase(), evs);
		return evs;
	}