@Override
  public Set<AlarmReceiver> getReceivers(Transport transport) {
    Set<AlarmReceiver> r = Sets.newHashSet();

    for (AlarmReceiver receiver : receivers) {
      String address = receiver.getAddress(transport);
      if (address != null && !address.isEmpty()) {
        r.add(receiver);
      }
    }

    return r;
  }
  @SuppressWarnings("unchecked")
  public <T, I> T getImplementationClass( //
      QueryClassLoader classLoader, //
      TemplateClassDefinition<T> templateDefinition, //
      String entireClass, //
      String materializedClassName)
      throws ClassTransformationException {

    final ClassSet set =
        new ClassSet(null, templateDefinition.getTemplateClassName(), materializedClassName);

    try {
      final byte[][] implementationClasses =
          classLoader.getClassByteCode(set.generated.clazz, entireClass);

      Map<String, ClassNode> classesToMerge = Maps.newHashMap();
      for (byte[] clazz : implementationClasses) {
        ClassNode node = getClassNodeFromByteCode(clazz);
        classesToMerge.put(node.name, node);
      }

      LinkedList<ClassSet> names = Lists.newLinkedList();
      Set<ClassSet> namesCompleted = Sets.newHashSet();
      names.add(set);

      while (!names.isEmpty()) {
        final ClassSet nextSet = names.removeFirst();
        if (namesCompleted.contains(nextSet)) continue;
        final ClassNames nextPrecompiled = nextSet.precompiled;
        final byte[] precompiledBytes =
            byteCodeLoader.getClassByteCodeFromPath(nextPrecompiled.clazz);
        ClassNames nextGenerated = nextSet.generated;
        ClassNode generatedNode = classesToMerge.get(nextGenerated.slash);
        MergedClassResult result =
            MergeAdapter.getMergedClass(nextSet, precompiledBytes, generatedNode);

        for (String s : result.innerClasses) {
          s = s.replace(FileUtils.separatorChar, '.');
          names.add(nextSet.getChild(s));
        }
        classLoader.injectByteCode(nextGenerated.dot, result.bytes);
        namesCompleted.add(nextSet);
      }

      //      logger.debug(String.format("[Compile Time] Janino: %dms, Bytecode load and parse:
      // %dms, Class Merge: %dms, Subclass remap and load: %dms.",
      // t1.elapsed(TimeUnit.MILLISECONDS), t2.elapsed(TimeUnit.MILLISECONDS),
      // t3.elapsed(TimeUnit.MILLISECONDS), t4.elapsed(TimeUnit.MILLISECONDS)));

      Class<?> c = classLoader.findClass(set.generated.dot);
      if (templateDefinition.getExternalInterface().isAssignableFrom(c)) {
        return (T) c.newInstance();
      } else {
        throw new ClassTransformationException(
            "The requested class did not implement the expected interface.");
      }

    } catch (CompileException
        | IOException
        | ClassNotFoundException
        | InstantiationException
        | IllegalAccessException e) {
      throw new ClassTransformationException(
          String.format("Failure generating transformation classes for value: \n %s", entireClass),
          e);
    }
  }
  @Test
  public void createWithVisibilityFluo() throws Exception {
    final String sparql =
        "SELECT ?customer ?worker ?city "
            + "{ "
            + "?customer <http://talksTo> ?worker. "
            + "?worker <http://livesIn> ?city. "
            + "?worker <http://worksAt> <http://Chipotle>. "
            + "}";

    // Triples that will be streamed into Fluo after the PCJ has been created.
    final Map<RyaStatement, String> streamedTriples = new HashMap<>();
    addStatementVisibilityEntry(
        streamedTriples, makeRyaStatement("http://Alice", "http://talksTo", "http://Bob"), "A&B");
    addStatementVisibilityEntry(
        streamedTriples, makeRyaStatement("http://Bob", "http://livesIn", "http://London"), "A");
    addStatementVisibilityEntry(
        streamedTriples, makeRyaStatement("http://Bob", "http://worksAt", "http://Chipotle"), "B");

    addStatementVisibilityEntry(
        streamedTriples,
        makeRyaStatement("http://Alice", "http://talksTo", "http://Charlie"),
        "B&C");
    addStatementVisibilityEntry(
        streamedTriples,
        makeRyaStatement("http://Charlie", "http://livesIn", "http://London"),
        "B");
    addStatementVisibilityEntry(
        streamedTriples,
        makeRyaStatement("http://Charlie", "http://worksAt", "http://Chipotle"),
        "C");

    addStatementVisibilityEntry(
        streamedTriples, makeRyaStatement("http://Alice", "http://talksTo", "http://David"), "C&D");
    addStatementVisibilityEntry(
        streamedTriples, makeRyaStatement("http://David", "http://livesIn", "http://London"), "C");
    addStatementVisibilityEntry(
        streamedTriples,
        makeRyaStatement("http://David", "http://worksAt", "http://Chipotle"),
        "D");

    addStatementVisibilityEntry(
        streamedTriples, makeRyaStatement("http://Alice", "http://talksTo", "http://Eve"), "D&E");
    addStatementVisibilityEntry(
        streamedTriples, makeRyaStatement("http://Eve", "http://livesIn", "http://Leeds"), "D");
    addStatementVisibilityEntry(
        streamedTriples, makeRyaStatement("http://Eve", "http://worksAt", "http://Chipotle"), "E");

    addStatementVisibilityEntry(
        streamedTriples, makeRyaStatement("http://Frank", "http://talksTo", "http://Alice"), "");
    addStatementVisibilityEntry(
        streamedTriples, makeRyaStatement("http://Frank", "http://livesIn", "http://London"), "");
    addStatementVisibilityEntry(
        streamedTriples, makeRyaStatement("http://Frank", "http://worksAt", "http://Chipotle"), "");

    // Create the PCJ Table in Accumulo.
    final PrecomputedJoinStorage rootStorage =
        new AccumuloPcjStorage(accumuloConn, RYA_INSTANCE_NAME);
    final String pcjId = rootStorage.createPcj(sparql);

    // Create the PCJ in Fluo.
    new CreatePcj()
        .withRyaIntegration(pcjId, rootStorage, fluoClient, accumuloConn, RYA_INSTANCE_NAME);

    // Stream the data into Fluo.
    for (final RyaStatement statement : streamedTriples.keySet()) {
      final Optional<String> visibility = Optional.of(streamedTriples.get(statement));
      new InsertTriples().insert(fluoClient, statement, visibility);
    }

    // Fetch the exported results from Accumulo once the observers finish working.
    fluo.waitForObservers();

    setupTestUsers(accumuloConn, RYA_INSTANCE_NAME, pcjId);

    // Verify ABCDE using root.
    final Set<BindingSet> rootResults = toSet(rootStorage.listResults(pcjId));

    final Set<BindingSet> rootExpected = Sets.newHashSet();
    rootExpected.add(
        makeBindingSet(
            new BindingImpl("customer", new URIImpl("http://Alice")),
            new BindingImpl("worker", new URIImpl("http://Bob")),
            new BindingImpl("city", new URIImpl("http://London"))));
    rootExpected.add(
        makeBindingSet(
            new BindingImpl("customer", new URIImpl("http://Alice")),
            new BindingImpl("worker", new URIImpl("http://Charlie")),
            new BindingImpl("city", new URIImpl("http://London"))));
    rootExpected.add(
        makeBindingSet(
            new BindingImpl("customer", new URIImpl("http://Alice")),
            new BindingImpl("worker", new URIImpl("http://Eve")),
            new BindingImpl("city", new URIImpl("http://Leeds"))));
    rootExpected.add(
        makeBindingSet(
            new BindingImpl("customer", new URIImpl("http://Alice")),
            new BindingImpl("worker", new URIImpl("http://David")),
            new BindingImpl("city", new URIImpl("http://London"))));

    assertEquals(rootExpected, rootResults);

    // Verify AB
    final Connector abConn = cluster.getConnector("abUser", "password");
    final PrecomputedJoinStorage abStorage = new AccumuloPcjStorage(abConn, RYA_INSTANCE_NAME);
    final Set<BindingSet> abResults = toSet(abStorage.listResults(pcjId));

    final Set<BindingSet> abExpected = Sets.newHashSet();
    abExpected.add(
        makeBindingSet(
            new BindingImpl("customer", new URIImpl("http://Alice")),
            new BindingImpl("worker", new URIImpl("http://Bob")),
            new BindingImpl("city", new URIImpl("http://London"))));

    assertEquals(abExpected, abResults);

    // Verify ABC
    final Connector abcConn = cluster.getConnector("abcUser", "password");
    final PrecomputedJoinStorage abcStorage = new AccumuloPcjStorage(abcConn, RYA_INSTANCE_NAME);
    final Set<BindingSet> abcResults = toSet(abcStorage.listResults(pcjId));

    final Set<BindingSet> abcExpected = Sets.newHashSet();
    abcExpected.add(
        makeBindingSet(
            new BindingImpl("customer", new URIImpl("http://Alice")),
            new BindingImpl("worker", new URIImpl("http://Bob")),
            new BindingImpl("city", new URIImpl("http://London"))));
    abcExpected.add(
        makeBindingSet(
            new BindingImpl("customer", new URIImpl("http://Alice")),
            new BindingImpl("worker", new URIImpl("http://Charlie")),
            new BindingImpl("city", new URIImpl("http://London"))));

    assertEquals(abcExpected, abcResults);

    // Verify ADE
    final Connector adeConn = cluster.getConnector("adeUser", "password");
    final PrecomputedJoinStorage adeStorage = new AccumuloPcjStorage(adeConn, RYA_INSTANCE_NAME);
    final Set<BindingSet> adeResults = toSet(adeStorage.listResults(pcjId));

    final Set<BindingSet> adeExpected = Sets.newHashSet();
    adeExpected.add(
        makeBindingSet(
            new BindingImpl("customer", new URIImpl("http://Alice")),
            new BindingImpl("worker", new URIImpl("http://Eve")),
            new BindingImpl("city", new URIImpl("http://Leeds"))));

    assertEquals(adeExpected, adeResults);

    // Verify no auths.
    final Connector noAuthConn = cluster.getConnector("noAuth", "password");
    final PrecomputedJoinStorage noAuthStorage =
        new AccumuloPcjStorage(noAuthConn, RYA_INSTANCE_NAME);
    final Set<BindingSet> noAuthResults = toSet(noAuthStorage.listResults(pcjId));
    assertTrue(noAuthResults.isEmpty());
  }
  @Override
  public ScoreboardContent computeScoreboardContent(
      Contest contest,
      ScoreboardState state,
      List<ProgrammingSubmission> submissions,
      Map<String, Date> contestantStartTimes,
      Map<String, URL> userJidToImageMap) {

    ICPCContestStyleConfig icpcStyleConfig = (ICPCContestStyleConfig) contest.getStyleConfig();
    ScoreboardEntryComparator<ICPCScoreboardEntry> comparator = new ICPCScoreboardEntryComparator();

    Map<String, Map<String, Integer>> attemptsMap = Maps.newHashMap();
    Map<String, Map<String, Long>> penaltyMap = Maps.newHashMap();
    Map<String, Map<String, Integer>> problemStateMap = Maps.newHashMap();
    Map<String, Long> lastAcceptedPenaltyMap = Maps.newHashMap();
    Set<String> acceptedProblemJids = Sets.newHashSet();

    for (String contestantJid : state.getContestantJids()) {
      attemptsMap.put(contestantJid, Maps.newHashMap());
      penaltyMap.put(contestantJid, Maps.newHashMap());
      problemStateMap.put(contestantJid, Maps.newHashMap());

      for (String problemJid : state.getProblemJids()) {
        attemptsMap.get(contestantJid).put(problemJid, 0);
        penaltyMap.get(contestantJid).put(problemJid, 0L);
        lastAcceptedPenaltyMap.put(contestantJid, 0L);
        problemStateMap
            .get(contestantJid)
            .put(problemJid, ICPCScoreboardEntry.State.NOT_ACCEPTED.ordinal());
      }
    }

    for (ProgrammingSubmission submission : submissions) {
      String contestantJid = submission.getAuthorJid();
      String problemJid = submission.getProblemJid();

      if (!attemptsMap.containsKey(contestantJid)) {
        continue;
      }
      if (!attemptsMap.get(contestantJid).containsKey(problemJid)) {
        continue;
      }
      if (problemStateMap.get(contestantJid).get(problemJid)
          != ICPCScoreboardEntry.State.NOT_ACCEPTED.ordinal()) {
        continue;
      }

      Verdict verdict = submission.getLatestVerdict();

      if (verdict.getCode().equals("?")) {
        continue;
      }

      int attempts = attemptsMap.get(contestantJid).get(problemJid);
      attemptsMap.get(contestantJid).put(problemJid, attempts + 1);

      long penaltyInMilliseconds =
          computeSubmissionPenaltyInMilliseconds(
              contest, contestantStartTimes.get(contestantJid), submission.getTime());
      penaltyMap.get(contestantJid).put(problemJid, convertPenaltyToMinutes(penaltyInMilliseconds));

      if (verdict.getCode().equals("AC")) {
        if (acceptedProblemJids.contains(problemJid)) {
          problemStateMap
              .get(contestantJid)
              .put(problemJid, ICPCScoreboardEntry.State.ACCEPTED.ordinal());
        } else {
          problemStateMap
              .get(contestantJid)
              .put(problemJid, ICPCScoreboardEntry.State.FIRST_ACCEPTED.ordinal());
          acceptedProblemJids.add(problemJid);
        }

        lastAcceptedPenaltyMap.put(contestantJid, penaltyInMilliseconds);
      }
    }

    List<ICPCScoreboardEntry> entries = Lists.newArrayList();

    for (String contestantJid : state.getContestantJids()) {
      ICPCScoreboardEntry entry = new ICPCScoreboardEntry();
      entry.contestantJid = contestantJid;
      entry.imageURL = userJidToImageMap.get(contestantJid);

      for (String problemJid : state.getProblemJids()) {
        int attempts = attemptsMap.get(contestantJid).get(problemJid);
        long penalty = penaltyMap.get(contestantJid).get(problemJid);
        long lastAcceptedPenalty = lastAcceptedPenaltyMap.get(contestantJid);
        int problemState = problemStateMap.get(contestantJid).get(problemJid);

        entry.attemptsList.add(attempts);
        entry.penaltyList.add(penalty);
        entry.lastAcceptedPenalty = lastAcceptedPenalty;
        entry.problemStateList.add(problemState);

        if (problemState != ICPCScoreboardEntry.State.NOT_ACCEPTED.ordinal()) {
          entry.totalAccepted++;
          entry.totalPenalties +=
              icpcStyleConfig.getWrongSubmissionPenalty() * (attempts - 1) + penalty;
        }
      }

      entries.add(entry);
    }

    sortEntriesAndAssignRanks(comparator, entries);

    return new ICPCScoreboardContent(entries);
  }