<commit_before>var debug = require('debug')('graph-generator');

var _ = require('underscore');
var async = require('async');

var githubFacade = require('../../shared/api/facade-github-octonode');
var Graph = require("./graph-model");

module.exports = function(config) {

  var api = githubFacade(config);

  return {

    generateInSeq: function(owner, depth, callback) {
      var graph = new Graph();
      var visited = [];
      var currentDepth = 1;
      var maxDepth = adjustDepth(depth);

      runSeq([owner], callback);

      // TODO Optional: I could store the level info directly in my graph structure for optimization

      function runSeq(peers, callback) {
        var nextLevelPeers = [];
        var thisLevelPeersNumber = peers.length;

        debug('The number of peers for processing on level ' + currentDepth + ' is ' + thisLevelPeersNumber);
        async.eachSeries(peers, function(peer, done) {
          debug('Processing peer: ' + peer);
          var following;
          thisLevelPeersNumber--;
          if (_.contains(visited, peer)) {
            done();
            //return;
          } else {
            visited.push(peer);

            // These are going to be parallel async calls
            following = api.following(peer, function(err, following) {
              debug(peer + ' data obtained');              
              var names = _.pluck(following, 'login');
              graph.addEdges(peer, names);
              nextLevelPeers = nextLevelPeers.concat(names);

              if (thisLevelPeersNumber > 0) {
                done();
              } else {
                (++currentDepth > maxDepth) ? callback(null, graph) : runSeq(nextLevelPeers, callback)
              }
            });
          }
        })
      }

    },

    generateInParallel: function(owner, depth, callback) {
      var graph = new Graph();
      var visited = [];
      var currentDepth = 1;
      var maxDepth = adjustDepth(depth);

      runParallel([owner], callback);

      function runParallel(peers, callback) {
        var nextLevelPeers = [];
        var thisLevelPeersNumber = peers.length;

        debug('The number of peers for processing on level ' + currentDepth + ' is ' + thisLevelPeersNumber);
        peers.forEach(function(peer) {
          debug('Processing peer: ' + peer);
          var following;
          if (_.contains(visited, peer)) {
            thisLevelPeersNumber--;
            return;
          } else {
            visited.push(peer);
            // These are going to be parallel async calls
            following = api.following(peer, function(err, following, headers) {
              debug(peer + ' data obtained');              
              thisLevelPeersNumber--;
              var names = _.pluck(following, 'login');
              graph.addEdges(peer, names);
              nextLevelPeers = nextLevelPeers.concat(names);
              if (thisLevelPeersNumber === 0) {
                (++currentDepth > maxDepth) ? callback(null, graph) : runParallel(nextLevelPeers, callback)
              }
            });
          }
        })
      }
    }
  }
}

function adjustDepth(depth) {
  // If not correct do not throw just works with the smallest possible depth
  return (depth < 1 || depth > 3) ?  1 : depth
}<commit_msg>fix for empty following<commit_after>var debug = require('debug')('graph-generator');

var _ = require('underscore');
var async = require('async');

var githubFacade = require('../../shared/api/facade-github-octonode');
var Graph = require("./graph-model");

module.exports = function(config) {

  var api = githubFacade(config);

  return {

    generateInSeq: function(owner, depth, callback) {
      var graph = new Graph();
      var visited = [];
      var currentDepth = 1;
      var maxDepth = adjustDepth(depth);

      runSeq([owner], callback);

      // TODO Optional: I could store the level info directly in my graph structure for optimization

      function runSeq(peers, callback) {
        var nextLevelPeers = [];
        var thisLevelPeersNumber = peers.length;

        debug('The number of peers for processing on level ' + currentDepth + ' is ' + thisLevelPeersNumber);
        async.eachSeries(peers, function(peer, done) {
          debug('Processing peer: ' + peer);
          var following;
          thisLevelPeersNumber--;
          if (_.contains(visited, peer)) {
            done();
            //return;
          } else {
            visited.push(peer);

            // These are going to be parallel async calls
            following = api.following(peer, function(err, following) {
              debug(peer + ' data obtained');
              var names;
              if (following.length === 0) {
                graph.addEdges(peer, following);
              } else {
                names = _.pluck(following, 'login');
                graph.addEdges(peer, names);
                nextLevelPeers = nextLevelPeers.concat(names);
              }
              if (thisLevelPeersNumber > 0) {
                done();
              } else {
                (++currentDepth > maxDepth) ? callback(null, graph) : runSeq(nextLevelPeers, callback)
              }
            });
          }
        })
      }

    },

    generateInParallel: function(owner, depth, callback) {
      var graph = new Graph();
      var visited = [];
      var currentDepth = 1;
      var maxDepth = adjustDepth(depth);
      
      runParallel([owner], callback);

      function runParallel(peers, callback) {
        var nextLevelPeers = [];
        var thisLevelPeersNumber = peers.length;

        debug('The number of peers for processing on level ' + currentDepth + ' is ' + thisLevelPeersNumber);
        peers.forEach(function(peer) {
          debug('Processing peer: ' + peer);
          var following;
          if (_.contains(visited, peer)) {
            thisLevelPeersNumber--;
            return;
          } else {
            visited.push(peer);
            // These are going to be parallel async calls
            following = api.following(peer, function(err, following, headers) {
              debug(peer + ' data obtained');
              var names;
              thisLevelPeersNumber--;
              if (following.length === 0) {
                graph.addEdges(peer, following);
              } else {
                names = _.pluck(following, 'login');
                graph.addEdges(peer, names);
                nextLevelPeers = nextLevelPeers.concat(names);
              }
              if (thisLevelPeersNumber === 0) {
                (++currentDepth > maxDepth) ? callback(null, graph) : runParallel(nextLevelPeers, callback)
              }
            });
          }
        })
      }
    }
  }
}

function adjustDepth(depth) {
  // If not correct do not throw just works with the smallest possible depth
  return (depth < 1 || depth > 3) ? 1 : depth
}
{'fraction_non_alphanumeric': 0.1127536231884058, 'fraction_numerical': 0.002318840579710145, 'mean_word_length': 1.8754166666666667, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '643633', 'n_tokens_mistral': 1828, 'n_tokens_neox': 1769, 'n_words': 473}