public static void main(String[] args) throws IOException, ExecutionException, InterruptedException
  {
    log.info("Loading data.");
    final Map<String, Repository> repositories = DataLoader.loadRepositories();
    final DataSet data_set = DataLoader.loadWatchings();

    if (args.length > 0)
    {
      // Perform cross-validation.
      final List<DataSet> folds = data_set.stratify(100);
      for (int i = 0; i < folds.size(); i++)
      {
        log.info(String.format("Starting fold %d.", i + 1));
        final DataSet test_set = folds.remove(0);
        final DataSet training_set = DataSet.combine(folds);

        log.info("Training");
        final NearestNeighbors knn = new NearestNeighbors(training_set);

        log.info("Classifying");
        final Map<String, Map<String, Collection<Float>>> evaluations = knn.evaluate(test_set.getWatchers().values());

        final Set<Watcher> prediction = NearestNeighbors.predict(knn, evaluations, 10, test_set.getWatchers());
        final Set<Watcher> all_predictions = NearestNeighbors.predict(knn, evaluations, 1000, test_set.getWatchers());

        analyze(test_set, training_set, prediction, all_predictions, knn, evaluations);

        log.info(String.format(">>> Results for fold %d: %f%% / %f%%", i + 1, NearestNeighbors.score(test_set, prediction) * 100, NearestNeighbors.score(test_set, all_predictions) * 100));

        folds.add(test_set);

        write_predictions(prediction);
      }
    }

    else
    {

      log.info("Training.");
      final NearestNeighbors knn = new NearestNeighbors(data_set);

      log.info("Evaluating.");
      final Set<Watcher> predictings = DataLoader.loadPredictings();
      final Map<String, Map<String, Collection<Float>>> evaluations = knn.evaluate(predictings);
      final Set<Watcher> predictions = NearestNeighbors.predict(knn, evaluations, 10, null);

      final List<Map.Entry<String, NeighborRegion>> sorted_regions = MyUtils.sortRegionsByPopularity(knn.training_regions, new Comparator<Map.Entry<String, NeighborRegion>>(){

        public int compare(final Map.Entry<String, NeighborRegion> first, final Map.Entry<String, NeighborRegion> second)
        {
          int firstValue = first.getValue().watchers.size();
          int secondValue = second.getValue().watchers.size();

          if (secondValue > firstValue)
          {
            return 1;
          }
          else if (firstValue < secondValue)
          {
            return -1;
          }

          return 0;
        }
      });

      // Fill in repositories for any watchers with fewer than 10 repos.
      log.info("Filling in repositories");
      for (final Watcher w : predictions)
      {
        if (w.repositories.size() < 10)
        {
          for (final Map.Entry<String, NeighborRegion> pair : sorted_regions)
          {
            final NeighborRegion region = pair.getValue();
            if (!region.most_forked.watchers.contains(w))
            {
              w.associate(region.most_forked);
            }

            if (w.repositories.size() == 10)
            {
              break;
            }
          }
        }
      }

      log.info ("Printing results file.");
      write_predictions(predictions);
      /*

 #repos_by_popularity = []
 #sorted_regions = knn.training_regions.values.sort { |x,y| y.most_popular.watchers.size <=> x.most_popular.watchers.size }
 #repos_by_popularity = sorted_regions.collect {|x| x.most_popular.id}
 #
 #$LOG.info "Printing results file."
 #File.open('results.txt', 'w') do |file|
 #
 #  predictions.each do |watcher|
 #    # Add the ten most popular repositories that the user is not already a watcher of to his repo list if
 #    # we don't have any predictions.
 #    if watcher.repositories.empty?
 #      if knn.training_watchers[watcher.id].nil?
 #        puts "No data for watcher: #{watcher.id}"
 #        repos_by_popularity[0..10].each do |repo_id|
 #          watcher.repositories << repo_id
 #        end
 #      else
 #        added_repo_count = 0
 #        repos_by_popularity.each do |suggested_repo_id|
 #          unless knn.training_watchers[watcher.id].repositories.include?(suggested_repo_id)
 #            watcher.repositories << suggested_repo_id
 #            added_repo_count += 1
 #          end
 #
 #          break if added_repo_count == 10
 #        end
 #      end
 #    end
 #
 ##    $LOG.debug "Score (#{watcher.id}): #{NearestNeighbors.accuracy(knn.training_watchers[watcher.id], watcher)} -- #{watcher.to_s}"
 #    file.puts watcher.to_s
 #  end
 #end
      */
    }

    System.exit(0);
  }