code: public static <T extends MatchResult, S extends MatchType> Predicate<T> withinRange(S minMatchType, BoundType minBound, S maxMatchType, BoundType maxBound) {
  
          Predicate<T> lowerPredicate;
          Predicate<T> upperPredicate;
  
          if (minBound.equals(BoundType.CLOSED)) {
              lowerPredicate = greaterOrEqualTo(minMatchType);
          } else {
              lowerPredicate = greaterThan(minMatchType);
          }
  
          if (maxBound.equals(BoundType.CLOSED)) {
              upperPredicate = lowerOrEqualTo(maxMatchType);
          } else {
              upperPredicate = lowerThan(maxMatchType);
          }
  
          return Predicates.and(lowerPredicate, upperPredicate);
      }
docs: Generates a Predicate that only accepts the Match Results within a range. The range may be closed or open at each
  of the boundaries. {@code BoundType.CLOSED} means that the boundary should also be accepted. {@code BoundType.OPEN}
  on the other indicates that the boundary itself should not be accepted.
  
  @param minMatchType the matchType that defines the lower boundary
  @param minBound     the lower {@code BoundType}
  @param maxMatchType the matchType that defines the upper boundary
  @param maxBound     the upper {@code BoundType}
  @param <T>          a subclass of MatchResult
  @param <S>          a subclass of MatchType
  @return the Predicate