private Predicates getPredicates(Step step, Traversal.Admin traversal) {
    Predicates predicates = new Predicates();
    Step<?, ?> nextStep = step.getNextStep();

    while (true) {
      if (nextStep instanceof HasContainerHolder) {
        HasContainerHolder hasContainerHolder = (HasContainerHolder) nextStep;
        boolean skip = false;
        for (HasContainer has : hasContainerHolder.getHasContainers())
          if (has.getPredicate().getTraversals().size() > 0) skip = true;

        if (!skip) {
          hasContainerHolder.getHasContainers().forEach((has) -> predicates.hasContainers.add(has));
          nextStep.getLabels().forEach(label -> predicates.labels.add(label.toString()));
          traversal.removeStep(nextStep);
        }
      } else if (nextStep instanceof RangeGlobalStep) {
        RangeGlobalStep rangeGlobalStep = (RangeGlobalStep) nextStep;
        predicates.limitLow = rangeGlobalStep.getLowRange();
        predicates.limitHigh = rangeGlobalStep.getHighRange();
        traversal.removeStep(nextStep);
      } else return predicates;

      nextStep = nextStep.getNextStep();
    }
  }
 public static <S, E> void removeToTraversal(
     final Step<S, ?> startStep,
     final Step<?, E> endStep,
     final Traversal.Admin<S, E> newTraversal) {
   final Traversal.Admin<?, ?> originalTraversal = startStep.getTraversal();
   Step<?, ?> currentStep = startStep;
   while (currentStep != endStep && !(currentStep instanceof EmptyStep)) {
     final Step<?, ?> temp = currentStep.getNextStep();
     originalTraversal.removeStep(currentStep);
     newTraversal.addStep(currentStep);
     currentStep = temp;
   }
 }
 @Override
 public void apply(final Traversal.Admin<?, ?> traversal) {
   final TraversalParent parent = traversal.getParent();
   int size = traversal.getSteps().size();
   Step prev = null;
   for (int i = 0; i < size; i++) {
     final Step curr = traversal.getSteps().get(i);
     if (curr instanceof CountGlobalStep && i < size - 1) {
       final Step next = traversal.getSteps().get(i + 1);
       if (next instanceof IsStep
           && !(prev
               instanceof
               RangeGlobalStep)) { // if a RangeStep was provided, assume that the user knows what
                                   // he's doing
         final IsStep isStep = (IsStep) next;
         final P isStepPredicate = isStep.getPredicate();
         Long highRange = null;
         boolean useNotStep = false;
         for (P p :
             isStepPredicate instanceof ConnectiveP
                 ? ((ConnectiveP<?>) isStepPredicate).getPredicates()
                 : Collections.singletonList(isStepPredicate)) {
           final Object value = p.getValue();
           final BiPredicate predicate = p.getBiPredicate();
           if (value instanceof Number) {
             final long highRangeOffset =
                 INCREASED_OFFSET_SCALAR_PREDICATES.contains(predicate) ? 1L : 0L;
             final Long highRangeCandidate = ((Number) value).longValue() + highRangeOffset;
             final boolean update = highRange == null || highRangeCandidate > highRange;
             if (update) {
               if (parent instanceof EmptyStep) {
                 useNotStep = true;
               } else {
                 if (parent instanceof RepeatStep) {
                   final RepeatStep repeatStep = (RepeatStep) parent;
                   useNotStep =
                       Objects.equals(traversal, repeatStep.getUntilTraversal())
                           || Objects.equals(traversal, repeatStep.getEmitTraversal());
                 } else {
                   useNotStep = parent instanceof FilterStep || parent instanceof SideEffectStep;
                 }
               }
               highRange = highRangeCandidate;
               useNotStep &=
                   curr.getLabels().isEmpty()
                       && next.getLabels().isEmpty()
                       && next.getNextStep() instanceof EmptyStep
                       && ((highRange <= 1L && predicate.equals(Compare.lt))
                           || (highRange == 1L
                               && (predicate.equals(Compare.eq)
                                   || predicate.equals(Compare.lte))));
             }
           } else {
             final Long highRangeOffset = RANGE_PREDICATES.get(predicate);
             if (value instanceof Collection && highRangeOffset != null) {
               final Object high = Collections.max((Collection) value);
               if (high instanceof Number) {
                 final Long highRangeCandidate = ((Number) high).longValue() + highRangeOffset;
                 final boolean update = highRange == null || highRangeCandidate > highRange;
                 if (update) highRange = highRangeCandidate;
               }
             }
           }
         }
         if (highRange != null) {
           if (useNotStep) {
             traversal.asAdmin().removeStep(next); // IsStep
             traversal.asAdmin().removeStep(curr); // CountStep
             size -= 2;
             if (prev != null) {
               final Traversal.Admin inner = __.start().asAdmin();
               TraversalHelper.insertAfterStep(prev, inner.getStartStep(), inner);
               TraversalHelper.replaceStep(prev, new NotStep<>(traversal, inner), traversal);
             } else {
               traversal.asAdmin().addStep(new NotStep<>(traversal, __.identity()));
             }
           } else {
             TraversalHelper.insertBeforeStep(
                 new RangeGlobalStep<>(traversal, 0L, highRange), curr, traversal);
           }
           i++;
         }
       }
     }
     prev = curr;
   }
 }
 public static Step getNextNonIdentityStep(final Step start) {
   Step currentStep = start.getNextStep();
   // Skip over identity steps
   while (currentStep instanceof IdentityStep) currentStep = currentStep.getNextStep();
   return currentStep;
 }