class CustomizedCrosspointsTraverser extends HugeTraverser {

    private final EdgeRecord edgeResults;

    public CustomizedCrosspointsTraverser(HugeGraph graph) {
        super(graph);
        this.edgeResults = new EdgeRecord(false);
    }

    private static CrosspointsPaths intersectionPaths(List<HugeVertex> sources,
                                                      List<Path> paths,
                                                      long limit) {
        // Split paths by end vertices
        MultivaluedMap<Id, Id> endVertices = newMultivalueMap();
        for (Path path : paths) {
            List<Id> vertices = path.vertices();
            int length = vertices.size();
            endVertices.add(vertices.get(0), vertices.get(length - 1));
        }

        Set<Id> sourceIds = sources.stream().map(HugeVertex::id)
                                   .collect(Collectors.toSet());
        Set<Id> ids = endVertices.keySet();
        if (sourceIds.size() != ids.size() || !sourceIds.containsAll(ids)) {
            return CrosspointsPaths.EMPTY;
        }

        // Get intersection of end vertices
        Collection<Id> intersection = null;
        for (List<Id> ends : endVertices.values()) {
            if (intersection == null) {
                intersection = ends;
            } else {
                intersection = CollectionUtil.intersect(intersection, ends);
            }
            if (intersection == null || intersection.isEmpty()) {
                return CrosspointsPaths.EMPTY;
            }
        }
        assert intersection != null;
        // Limit intersection number to limit crosspoints vertices in result
        int size = intersection.size();
        if (limit != NO_LIMIT && size > limit) {
            intersection = newList(intersection).subList(0, size - 1);
        }

        // Filter intersection paths
        List<Path> results = newList();
        for (Path path : paths) {
            List<Id> vertices = path.vertices();
            int length = vertices.size();
            if (intersection.contains(vertices.get(length - 1))) {
                results.add(path);
            }
        }
        return new CrosspointsPaths(newSet(intersection), results);
    }

    public EdgeRecord edgeResults() {
        return edgeResults;
    }

    public CrosspointsPaths crosspointsPaths(Iterator<Vertex> vertices,
                                             List<PathPattern> pathPatterns,
                                             long capacity, long limit) {<FILL_FUNCTION_BODY>}

    public static class PathPattern {

        private final List<Step> steps;

        public PathPattern() {
            this.steps = newList();
        }

        public List<Step> steps() {
            return this.steps;
        }

        public int size() {
            return this.steps.size();
        }

        public void add(Step step) {
            this.steps.add(step);
        }
    }

    public static class Step {

        private final EdgeStep edgeStep;

        public Step(HugeGraph g, Directions direction, List<String> labels,
                    Map<String, Object> properties, long degree,
                    long skipDegree) {
            this.edgeStep = new EdgeStep(g, direction, labels, properties,
                                         degree, skipDegree);
        }
    }

    public static class CrosspointsPaths {

        private static final CrosspointsPaths EMPTY = new CrosspointsPaths(
                ImmutableSet.of(), ImmutableList.of()
        );

        private final Set<Id> crosspoints;
        private final List<Path> paths;

        public CrosspointsPaths(Set<Id> crosspoints, List<Path> paths) {
            this.crosspoints = crosspoints;
            this.paths = paths;
        }

        public Set<Id> crosspoints() {
            return this.crosspoints;
        }

        public List<Path> paths() {
            return this.paths;
        }
    }
}

        E.checkArgument(vertices.hasNext(),
                        "The source vertices can't be empty");
        E.checkArgument(!pathPatterns.isEmpty(),
                        "The steps pattern can't be empty");
        checkCapacity(capacity);
        checkLimit(limit);
        MultivaluedMap<Id, Node> initialSources = newMultivalueMap();
        List<HugeVertex> verticesList = newList();
        while (vertices.hasNext()) {
            HugeVertex vertex = (HugeVertex) vertices.next();
            verticesList.add(vertex);
            Node node = new Node(vertex.id(), null);
            initialSources.add(vertex.id(), node);
        }
        List<Path> paths = newList();
        long edgeCount = 0L;
        long vertexCount = 0L;

        for (PathPattern pathPattern : pathPatterns) {
            MultivaluedMap<Id, Node> sources = initialSources;
            int stepNum = pathPattern.size();
            long access = 0;
            MultivaluedMap<Id, Node> newVertices = null;
            for (Step step : pathPattern.steps()) {
                stepNum--;
                newVertices = newMultivalueMap();
                Iterator<Edge> edges;

                // Traversal vertices of previous level
                for (Map.Entry<Id, List<Node>> entry : sources.entrySet()) {
                    List<Node> adjacency = newList();
                    edges = this.edgesOfVertex(entry.getKey(), step.edgeStep);
                    vertexCount += 1;
                    while (edges.hasNext()) {
                        HugeEdge edge = (HugeEdge) edges.next();
                        edgeCount += 1;
                        Id target = edge.id().otherVertexId();

                        this.edgeResults.addEdge(entry.getKey(), target, edge);

                        for (Node n : entry.getValue()) {
                            // If have loop, skip target
                            if (n.contains(target)) {
                                continue;
                            }
                            Node newNode = new Node(target, n);
                            adjacency.add(newNode);

                            checkCapacity(capacity, ++access,
                                          "customized crosspoints");
                        }
                    }

                    // Add current node's adjacent nodes
                    for (Node node : adjacency) {
                        newVertices.add(node.id(), node);
                    }
                }
                // Re-init sources
                sources = newVertices;
            }
            assert stepNum == 0;
            assert newVertices != null;
            for (List<Node> nodes : newVertices.values()) {
                for (Node n : nodes) {
                    paths.add(new Path(n.path()));
                }
            }
        }
        this.vertexIterCounter.addAndGet(vertexCount);
        this.edgeIterCounter.addAndGet(edgeCount);
        return intersectionPaths(verticesList, paths, limit);
    
<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