class Traverser extends PathTraverser {

        protected final List<RepeatEdgeStep> steps;

        protected boolean withRing;

        protected int sourceIndex;
        protected int targetIndex;

        protected boolean sourceFinishOneStep;
        protected boolean targetFinishOneStep;

        public Traverser(HugeTraverser traverser, TraverseStrategy strategy,
                         Collection<Id> sources, Collection<Id> targets,
                         List<RepeatEdgeStep> steps, boolean withRing,
                         long capacity, long limit, boolean concurrent) {
            super(traverser, strategy, sources, targets, capacity, limit, concurrent);

            this.steps = steps;
            this.withRing = withRing;
            for (RepeatEdgeStep step : steps) {
                this.totalSteps += step.maxTimes();
            }

            this.sourceIndex = 0;
            this.targetIndex = this.steps.size() - 1;

            this.sourceFinishOneStep = false;
            this.targetFinishOneStep = false;
        }

        @Override
        public RepeatEdgeStep nextStep(boolean forward) {
            return forward ? this.forwardStep() : this.backwardStep();
        }

        @Override
        public void beforeTraverse(boolean forward) {
            this.clearNewVertices();
            this.reInitAllIfNeeded(forward);
        }

        @Override
        public void afterTraverse(EdgeStep step, boolean forward) {<FILL_FUNCTION_BODY>}

        @Override
        protected void processOneForForward(Id sourceV, Id targetV) {
            for (Node source : this.sources.get(sourceV)) {
                // If have loop, skip target
                if (!this.withRing && source.contains(targetV)) {
                    continue;
                }

                // If cross point exists, path found, concat them
                if (this.lastSuperStep() &&
                    this.targetsAll.containsKey(targetV)) {
                    for (Node target : this.targetsAll.get(targetV)) {
                        List<Id> path = joinPath(source, target, this.withRing);
                        if (!path.isEmpty()) {
                            this.paths.add(new Path(targetV, path));
                            if (this.reachLimit()) {
                                return;
                            }
                        }
                    }
                }

                // Add node to next start-nodes
                this.addNodeToNewVertices(targetV, new Node(targetV, source));
            }
        }

        @Override
        protected void processOneForBackward(Id sourceV, Id targetV) {
            for (Node source : this.targets.get(sourceV)) {
                // If have loop, skip target
                if (!this.withRing && source.contains(targetV)) {
                    continue;
                }

                // If cross point exists, path found, concat them
                if (this.lastSuperStep() &&
                    this.sourcesAll.containsKey(targetV)) {
                    for (Node target : this.sourcesAll.get(targetV)) {
                        List<Id> path = joinPath(source, target, this.withRing);
                        if (!path.isEmpty()) {
                            Path newPath = new Path(targetV, path);
                            newPath.reverse();
                            this.paths.add(newPath);
                            if (this.reachLimit()) {
                                return;
                            }
                        }
                    }
                }

                // Add node to next start-nodes
                this.addNodeToNewVertices(targetV, new Node(targetV, source));
            }
        }

        private void reInitAllIfNeeded(boolean forward) {
            if (forward) {
                /*
                 * Re-init source all if last forward finished one super step
                 * and current step is not last super step
                 */
                if (this.sourceFinishOneStep && !this.lastSuperStep()) {
                    this.sourcesAll = this.newMultiValueMap();
                    this.sourceFinishOneStep = false;
                }
            } else {
                /*
                 * Re-init target all if last forward finished one super step
                 * and current step is not last super step
                 */
                if (this.targetFinishOneStep && !this.lastSuperStep()) {
                    this.targetsAll = this.newMultiValueMap();
                    this.targetFinishOneStep = false;
                }
            }
        }

        @Override
        protected void reInitCurrentStepIfNeeded(EdgeStep step,
                                                 boolean forward) {
            RepeatEdgeStep currentStep = (RepeatEdgeStep) step;
            currentStep.decreaseTimes();
            if (forward) {
                // Re-init sources
                if (currentStep.remainTimes() > 0) {
                    this.sources = this.newVertices;
                } else {
                    this.sources = this.sourcesAll;
                    this.sourceFinishOneStep = true;
                }
            } else {
                // Re-init targets
                if (currentStep.remainTimes() > 0) {
                    this.targets = this.newVertices;
                } else {
                    this.targets = this.targetsAll;
                    this.targetFinishOneStep = true;
                }
            }
        }

        public RepeatEdgeStep forwardStep() {
            RepeatEdgeStep currentStep = null;
            // Find next step to backward
            for (int i = 0; i < this.steps.size(); i++) {
                RepeatEdgeStep step = this.steps.get(i);
                if (step.remainTimes() > 0) {
                    currentStep = step;
                    this.sourceIndex = i;
                    break;
                }
            }
            return currentStep;
        }

        public RepeatEdgeStep backwardStep() {
            RepeatEdgeStep currentStep = null;
            // Find next step to backward
            for (int i = this.steps.size() - 1; i >= 0; i--) {
                RepeatEdgeStep step = this.steps.get(i);
                if (step.remainTimes() > 0) {
                    currentStep = step;
                    this.targetIndex = i;
                    break;
                }
            }
            return currentStep;
        }

        public boolean lastSuperStep() {
            return this.targetIndex == this.sourceIndex ||
                   this.targetIndex == this.sourceIndex + 1;
        }
    }


            Map<Id, List<Node>> all = forward ? this.sourcesAll :
                                      this.targetsAll;
            this.addNewVerticesToAll(all);
            this.reInitCurrentStepIfNeeded(step, forward);
            this.stepCount++;
        
<methods>public void <init>(org.apache.hugegraph.HugeGraph) ,public static void checkCapacity(long) ,public static void checkCapacity(long, long, java.lang.String) ,public static void checkDegree(long) ,public static void checkLimit(long) ,public static void checkNonNegative(long, java.lang.String) ,public static void checkNonNegativeOrNoLimit(long, java.lang.String) ,public static void checkPositive(long, java.lang.String) ,public static void checkPositiveOrNoLimit(long, java.lang.String) ,public static void checkSkipDegree(long, long, long) ,public static void checkTraverseMode(java.lang.String) ,public Iterator<Edge> createNestedIterator(org.apache.hugegraph.backend.id.Id, org.apache.hugegraph.traversal.algorithm.steps.Steps, int, Set<org.apache.hugegraph.backend.id.Id>, boolean) ,public Iterator<Edge> edgesOfVertex(org.apache.hugegraph.backend.id.Id, org.apache.hugegraph.traversal.algorithm.steps.Steps) ,public org.apache.hugegraph.traversal.algorithm.HugeTraverser.EdgesIterator edgesOfVertices(Iterator<org.apache.hugegraph.backend.id.Id>, org.apache.hugegraph.type.define.Directions, List<org.apache.hugegraph.backend.id.Id>, long) ,public org.apache.hugegraph.HugeGraph graph() ,public static boolean isTraverseModeDFS(java.lang.String) ,public static List<org.apache.hugegraph.structure.HugeEdge> pathEdges(Iterator<Edge>, org.apache.hugegraph.structure.HugeEdge) ,public static Iterator<Edge> skipSuperNodeIfNeeded(Iterator<Edge>, long, long) ,public static Map<K,V> topN(Map<K,V>, boolean, long) <variables>public static final java.lang.String DEFAULT_CAPACITY,public static final java.lang.String DEFAULT_ELEMENTS_LIMIT,public static final java.lang.String DEFAULT_LIMIT,public static final java.lang.String DEFAULT_MAX_DEGREE,public static final int DEFAULT_MAX_DEPTH,public static final java.lang.String DEFAULT_PAGE_LIMIT,public static final java.lang.String DEFAULT_PATHS_LIMIT,public static final java.lang.String DEFAULT_SAMPLE,public static final java.lang.String DEFAULT_SKIP_DEGREE,public static final java.lang.String DEFAULT_WEIGHT,protected static final Logger LOG,protected static final int MAX_VERTICES,public static final long NO_LIMIT,public static final java.lang.String TRAVERSE_MODE_BFS,public static final java.lang.String TRAVERSE_MODE_DFS,private static org.apache.hugegraph.util.collection.CollectionFactory collectionFactory,public java.util.concurrent.atomic.AtomicLong edgeIterCounter,private final non-sealed org.apache.hugegraph.HugeGraph graph,public java.util.concurrent.atomic.AtomicLong vertexIterCounter