docs: protected SibTr.Suppressor.Decision suppress(String key, String variant)
    {
      SibTr.Suppressor.Decision decision = SibTr.Suppressor.Decision.makeDecision(key,variant);
  
      Details details = _emitMessageKeyAndInsertsTime.get(key); // get the details (if any) for the key
      
      // If the details weren't in the map, attempt to add a new details object now (if we lose the race
      // we'll set the details reference to the object created by the other thread)    
      if (details == null)
      {
        // This is a new message
        Details newDetails = new Details(getNow(),getInterval());
        details = _emitMessageKeyAndInsertsTime.putIfAbsent(key,newDetails);
        if (details == null)
        {
          // We won any race and our newDetails will be used as the details for this message 
          if (getInterval() == Long.MAX_VALUE)
          {
            // We're never going to emit the message after this
            decision.suppressFutureMesages(SibTr.Suppressor.Decision.INFINITE);
            return decision;
          }
          else
          {
            // We're going to emit message again, eventually
            decision.suppressFutureMesages((int)(getInterval()/MILLISECONDS_PER_MINUTE));
            return decision;
          }
        }
      }
  
      // There was already a Details object in the map, so we're not the first occurrence of the message
      synchronized(details) // Keep a consistent view over the details object while we make our decision and update it
      {
        if (details.getInterval() == Long.MAX_VALUE)
        {
          // We're never going to emit the message again
          decision.suppressThisMessage();
          return decision;
        }
        else
        {
          long now = getNow(); // Snapshot the current time (note: Needs to be done while we hold the details lock)
          
          // Is it time to re-emit the message?
          long interval = now - details.getEmitTime();
  
          if (interval > details.getInterval())
          {
            // It's been a long time since the message was *not* suppressed, so report if any were suppressed
  
            // Decide on what to do based on how many messages were actually suppressed
            int suppressedMessageCount = details.getNumberOfSuppressions(); // Remember, details counts the first unsuppressed as one of the instances
            if (suppressedMessageCount == 0)
            {
              // Reset the size of the time interval during which to suppress messages - the messages seems to be rare
              // in comparison to the time interval, so we're happy to see it occasionally
              details.resetInterval();
            }
            else if (suppressedMessageCount == 1)
            {
              // We need to report on the one we suppressed, but it's still rare so reset the time interval
              decision.reportEarlierSuppressedMessages(suppressedMessageCount
                                                      ,details.getFirstSuppressionTime()
                                                      ,details.getMostRecentSuppressionTime()
                                                      );
              details.resetInterval();
            }
            else
            {
              // It's happening a lot, we need to report on the suppressed messages, but double the time interval
              decision.reportEarlierSuppressedMessages(suppressedMessageCount
                                                      ,details.getFirstSuppressionTime()
                                                      ,details.getMostRecentSuppressionTime()
                                                      );
              details.doubleInterval();
            }
  
            // Reset the time we last emitted the messages (since we're not suppressing this instance of the message)
            details.resetEmitTime(now);
  
            // We need to say we're suppressing future messages (and now how long for)
            decision.suppressFutureMesages((int) (details.getInterval() / MILLISECONDS_PER_MINUTE));
  
            return decision;
          }
          else
          {
            // It's not long enough and not suppressed enough, so suppress this message
            details.incrementInstances(now);
            decision.suppressThisMessage();
            return decision;
          }
        }
      }      
    }