docs: function( roots, fn, directed ){
        directed = arguments.length === 1 && !$$.is.fn(fn) ? fn : directed;
        fn = $$.is.fn(fn) ? fn : function(){};
        var cy = this._private.cy;
        var v = $$.is.string(roots) ? this.filter(roots) : roots;
        var S = [];
        var connectedNodes = [];
        var connectedBy = {};
        var id2depth = {};
        var discovered = {};
        var j = 0;
        var found;
        var edges = this.edges();
        var nodes = this.nodes();
  
        // push v
        for( var i = 0; i < v.length; i++ ){
          if( v[i].isNode() ){
            S.push( v[i] );
  
            connectedNodes.push( v[i] );
            id2depth[ v[i].id() ] = 0;
          }
        }
  
        while( S.length !== 0 ){
          var v = S.pop();
  
          if( !discovered[ v.id() ] ){
            discovered[ v.id() ] = true;
  
            var depth = id2depth[ v.id() ];
  
            var ret = fn.call(v, j++, depth);
  
            if( ret === true ){
              found = v;
              break;
            }
  
            if( ret === false ){
              break;
            }
  
            var vwEdges = v.connectedEdges(directed ? '[source = "' + v.id() + '"]' : undefined).intersect( edges );
            
            for( var i = 0; i < vwEdges.length; i++ ){
              var e = vwEdges[i];
              var w = e.connectedNodes('[id != "' + v.id() + '"]').intersect( nodes );
  
              if( w.length !== 0 && !discovered[ w.id() ] ){
                w = w[0];
  
                S.push( w );
  
                id2depth[ w.id() ] = id2depth[ v.id() ] + 1;
  
                connectedNodes.push( w );
                connectedBy[ w.id() ] = e;
              }
            }
          }
        }
  
        var connectedEles = [];
  
        for( var i = 0; i < connectedNodes.length; i++ ){
          var node = connectedNodes[i];
          var edge = connectedBy[ node.id() ];
  
          if( edge ){
            connectedEles.push( edge );
          }
  
          connectedEles.push( node );
        }
  
        return {
          path: new $$.Collection( cy, connectedEles ),
          found: new $$.Collection( cy, found )
        }
      }