docs: private long reap(long reapAt, boolean isShutdownReap) {
          String methodName = "reap";
          if ( TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled() ) {
              Tr.debug(tc, methodName + " At [ " + toRelSec(initialAt, reapAt) + " (s) ] Force [ " + isShutdownReap + " ]");
              Tr.debug(tc, methodName +
                  " All [ " + storage.size() + " ]" +
                  " Pending Quick [ " + pendingQuickStorage.size() + " ]" +
                  " Pending Slow [ " + pendingSlowStorage.size() + " ]");
          }
  
          // Reap the quick pending closes ...
  
          long nextQuickReapDelay = REAP_DELAY_INDEFINITE;
          Iterator<ZipFileData> pendingQuick = pendingQuickStorage.values();
          while ( (nextQuickReapDelay == REAP_DELAY_INDEFINITE) && pendingQuick.hasNext() ) {
              ZipFileData nextPending = pendingQuick.next();
  
              long nextLastPendAt = nextPending.lastPendAt;
              long nextPendDuration = reapAt - nextLastPendAt;
  
              if ( isShutdownReap ) {
                  // Shutdown closes all pending, regardless of how long they have waited.
  
                  if ( TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled() ) {
                      Tr.debug(tc, methodName +
                              " Path [ " + nextPending.path + " ]" +
                              " Waiting [ " + toAbsSec(nextPendDuration) + " (s) ] (Quick): Forced");
                  }
  
                  pendingQuick.remove();
  
                  fullyClose(nextPending, reapAt, IS_SHUTDOWN_REAP);
  
              } else { // Normal reap.
                  if ( nextPendDuration > quickPendMin) { // Reached the shortest expiration?
                      if ( TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled() ) {
                          Tr.debug(tc, methodName +
                              " Path [ " + nextPending.path + " ]" +
                              " Waiting [ " + toAbsSec(nextPendDuration) + " (s) ] (Quick): Expired");
                      }
  
                      pendingQuick.remove();
  
                      fullyClose(nextPending, reapAt, IS_NOT_SHUTDOWN_REAP);
  
                  } else { // Not yet reached the shorted expiration.
                      if ( TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled() ) {
                          Tr.debug(tc, methodName +
                              " Path [ " + nextPending.path + " ]" +
                              " Waiting [ " + toAbsSec(nextPendDuration) + " (s) ]: Still Waiting");
                      }
  
                      if ( nextPendDuration < 0 ) {
                          nextPendDuration = 0; // Should never happen;
                      }
                      nextQuickReapDelay = quickPendMax - nextPendDuration;
                  }
              }
          }
  
          // Reap the slow pending closes ...
  
          long nextSlowReapDelay = REAP_DELAY_INDEFINITE;
          Iterator<ZipFileData> pendingSlow = pendingSlowStorage.values();
          while ( (nextSlowReapDelay == REAP_DELAY_INDEFINITE) && pendingSlow.hasNext() ) {
              ZipFileData nextPending = pendingSlow.next();
  
              long nextLastPendAt = nextPending.lastPendAt;
              long nextPendDuration = reapAt - nextLastPendAt;
  
              if ( isShutdownReap ) {
                  // Shutdown closes all pending, regardless of how long they have waited.
  
                  if ( TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled() ) {
                      Tr.debug(tc, methodName +
                              " Path [ " + nextPending.path + " ]" +
                              " Waiting [ " + toAbsSec(nextPendDuration) + " (s) ] (Slow): Forced");
                  }
  
                  pendingSlow.remove();
  
                  fullyClose(nextPending, reapAt, IS_SHUTDOWN_REAP);
  
              } else { // Normal reap.
                  if ( nextPendDuration > slowPendMin ) { // Reached the shortest expiration?
                      if ( TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled() ) {
                          Tr.debug(tc, methodName +
                              " Path [ " + nextPending.path + " ]" +
                              " Waiting [ " + toAbsSec(nextPendDuration) + " (s) ] (Slow): Expired");
                      }
  
                      pendingSlow.remove();
  
                      fullyClose(nextPending, reapAt, IS_NOT_SHUTDOWN_REAP);
  
                  } else { // Not yet reached the shorted expiration.
                      if ( TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled() ) {
                          Tr.debug(tc, methodName +
                              " Path [ " + nextPending.path + " ]" +
                              " Waiting [ " + toAbsSec(nextPendDuration) + " (s) ]: Still Waiting");
                      }
  
                      if ( nextPendDuration < 0 ) {
                          nextPendDuration = 0; // Should never happen;
                      }
                      nextSlowReapDelay = slowPendMax - nextPendDuration;
                  }
              }
          }
  
          // Maybe, move this into a different method, and invoke from the
          // shutdown thread?
          //
          // Placement here seems couples normal reaping with shutdown steps,
          // which seems off.
  
          if ( isShutdownReap ) {
              if ( TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled() ) {
                  Tr.debug(tc, methodName + " De-activating reaper");
              }
  
              // We have the lock: There can be no activity since receiving
              // the interrupted exception and setting the reaper inactive.
  
              // Note: Have to set this before pending the outstanding open zip files.
              //        Remove of the eldest is not performed while shutting down.
              setIsActive(false);
  
              setFinalAt(reapAt);
  
              // Since this is a shut-down reap, all pending closes were
              // forced close, regardless of how long they were waiting.
              // There are only dangling opens to handle.
  
              for ( ZipFileData mustBeOpenOrClosed : storage.values() ) {
                  String path = mustBeOpenOrClosed.path;
  
                  if ( mustBeOpenOrClosed.isFullyClosed() ) {
                      if ( TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled() ) {
                          Tr.debug(tc, methodName + " Closed [ " + path + " ]: No shutdown action");
                      }
                  } else {
                      if ( mustBeOpenOrClosed.isPending() ) {
                          if ( TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled() ) {
                              Tr.debug(tc, methodName + " Unexpected Pending [ " + path + " ]: Shutdown close");
                          }
                      } else {
                          if ( TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled() ) {
                              Tr.debug(tc, methodName +
                                  " Open [ " + path + " ] [ " + mustBeOpenOrClosed.getActiveOpens() + " ]:" +
                                  " Shutdown pend and close");
                          }
                          mustBeOpenOrClosed.enactClose(reapAt, ZipFileData.CLOSE_ALL);
                      }
  
                      fullyClose(mustBeOpenOrClosed, reapAt, IS_SHUTDOWN_REAP);
                  }
              }
  
              // Finalize the zip files, all of which should be closed.
              //
              // Display statistics for each of the zip files.
  
              for ( ZipFileData mustBeClosed : storage.values() ) {
                  mustBeClosed.setFinal(reapAt);
                  mustBeClosed.debugState();
              }
          }
  
          long nextReapDelay;
          boolean useQuick;
          if ( (nextQuickReapDelay < 0) && (nextSlowReapDelay < 0) ) {
              useQuick = true;
              nextReapDelay = REAP_DELAY_INDEFINITE;
          } else if ( nextQuickReapDelay < 0 ) {
              useQuick = false;
              nextReapDelay = nextSlowReapDelay;
          } else if ( nextSlowReapDelay < 0 ) {
              useQuick = true;
              nextReapDelay = nextQuickReapDelay;
          } else {
              if ( nextQuickReapDelay < nextSlowReapDelay ) {
                  useQuick = true;
                  nextReapDelay = nextQuickReapDelay;
              } else {
                  useQuick = false;
                  nextReapDelay = nextSlowReapDelay;
              }
          }
  
          if ( TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled() ) {
              String delayText =
                  ( (nextReapDelay == REAP_DELAY_INDEFINITE) ? "Indefinite" : toAbsSec(nextReapDelay) );
              String speedText =
                  ( useQuick ? "Quick" : "Slow" );
              Tr.debug(tc, methodName + " Next reap [ " + delayText + " (s) ] (" + speedText + ")");
          }
          return nextReapDelay;
      }