@Override
 public boolean apply(Game game, Ability source) {
   FilterCard protectionFilter = (FilterCard) ((ProtectionAbility) ability).getFilter();
   protectionFilter.add(new ColorPredicate(choice.getColor()));
   protectionFilter.setMessage(choice.getChoice());
   ((ProtectionAbility) ability).setFilter(protectionFilter);
   return super.apply(game, source);
 }
 @Override
 public boolean apply(Game game, Ability source) {
   Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source));
   if (creature != null) {
     FilterCard protectionFilter = (FilterCard) ((ProtectionAbility) ability).getFilter();
     protectionFilter.add(new ColorPredicate(choice.getColor()));
     protectionFilter.setMessage(choice.getChoice());
     ((ProtectionAbility) ability).setFilter(protectionFilter);
     creature.addAbility(ability, source.getSourceId(), game);
     return true;
   }
   return false;
 }
  public boolean applySearchAndExile(
      Game game, Ability source, String cardName, UUID targetPlayerId) {
    Player player = game.getPlayer(source.getControllerId());
    if (cardName != null && player != null) {
      Player targetPlayer = game.getPlayer(targetPlayerId);
      if (targetPlayer != null) {
        FilterCard filter = new FilterCard("card named " + cardName);
        filter.add(new NamePredicate(cardName));

        // cards in Graveyard
        int cardsCount = (cardName.isEmpty() ? 0 : targetPlayer.getGraveyard().count(filter, game));
        if (cardsCount > 0) {
          filter.setMessage(
              "card named " + cardName + " in the graveyard of " + targetPlayer.getName());
          TargetCardInGraveyard target =
              new TargetCardInGraveyard(
                  (graveyardExileOptional ? 0 : cardsCount), cardsCount, filter);
          if (player.choose(Outcome.Exile, targetPlayer.getGraveyard(), target, game)) {
            List<UUID> targets = target.getTargets();
            for (UUID targetId : targets) {
              Card targetCard = targetPlayer.getGraveyard().get(targetId, game);
              if (targetCard != null) {
                targetPlayer.getGraveyard().remove(targetCard);
                targetCard.moveToZone(Zone.EXILED, source.getId(), game, false);
              }
            }
          }
        }

        // cards in Hand
        cardsCount = (cardName.isEmpty() ? 0 : targetPlayer.getHand().count(filter, game));
        if (cardsCount > 0) {
          filter.setMessage("card named " + cardName + " in the hand of " + targetPlayer.getName());
          TargetCardInHand target = new TargetCardInHand(0, cardsCount, filter);
          if (player.choose(Outcome.Exile, targetPlayer.getHand(), target, game)) {
            List<UUID> targets = target.getTargets();
            for (UUID targetId : targets) {
              Card targetCard = targetPlayer.getHand().get(targetId, game);
              if (targetCard != null) {
                targetPlayer.getHand().remove(targetCard);
                targetCard.moveToZone(Zone.EXILED, source.getId(), game, false);
              }
            }
          }
        } else {
          if (targetPlayer.getHand().size() > 0) {
            player.lookAtCards(targetPlayer.getName() + " hand", targetPlayer.getHand(), game);
          }
        }

        // cards in Library
        Cards cardsInLibrary = new CardsImpl(Zone.LIBRARY);
        cardsInLibrary.addAll(targetPlayer.getLibrary().getCards(game));
        cardsCount = (cardName.isEmpty() ? 0 : cardsInLibrary.count(filter, game));
        if (cardsCount > 0) {
          filter.setMessage(
              "card named " + cardName + " in the library of " + targetPlayer.getName());
          TargetCardInLibrary target = new TargetCardInLibrary(0, cardsCount, filter);
          if (player.choose(Outcome.Exile, cardsInLibrary, target, game)) {
            List<UUID> targets = target.getTargets();
            for (UUID targetId : targets) {
              Card targetCard = targetPlayer.getLibrary().remove(targetId, game);
              if (targetCard != null) {
                targetCard.moveToZone(Zone.EXILED, source.getId(), game, false);
              }
            }
          }
        } else {
          player.lookAtCards(targetPlayer.getName() + " library", cardsInLibrary, game);
        }
      }

      targetPlayer.shuffleLibrary(game);

      return true;
    }

    return false;
  }