echo "Grouping last {$limit} matches' stage data into match documents...\n\n";
 /**
  *   Groups checkin data and populates the `checkin_data_grouped` collection.
  */
 array_walk($checkin_data_arr, function ($checkin_doc) use($app, &$match_stages_grouped) {
     $checkin = new \BarracksMaster\Checkin($checkin_doc);
     /**
      *   There is no matchID for stage 1 checkin data.
      */
     if (empty($checkin->matchID)) {
         return;
     }
     if (empty($match_stages_grouped[$checkin->matchID])) {
         $match_stages_grouped[$checkin->matchID] = array('match_id' => $checkin->matchID);
     }
     $match_stages_grouped[$checkin->matchID]['stage_' . $checkin->getStage()] = $checkin;
     /**
      *   Mark the raw `checkin_data` doc as 'grouped', which is similar to 'processed'.
      */
     $checkin_doc['grouped'] = true;
     $app['mongo.db']->selectCollection('checkin_data')->save($checkin_doc);
 });
 /**
  *   Insert grouped match data into `checkin_data_grouped`
  */
 $insert_result = $app['mongo.db']->selectCollection('checkin_data_grouped')->batchInsert($match_stages_grouped);
 echo "\n\n" . sizeof($match_stages_grouped) . " checkin groups have been created.\n\n";
 /**
  *   Part 2: Determine matches that were shorter than 8 minutes.
  */
 $short_matches = array_filter($match_stages_grouped, function ($grouped_match) {
use BarracksMaster\PlayerProfile;
use BarracksMaster\Ladder;
$app->get('/tasks/update_ladder', function () use($app) {
    $fresh_checkin_data = $app['mongo.db']->selectCollection('checkin_data')->find(array('processed' => ['$ne' => true], 'stage' => '3'));
    if (!$fresh_checkin_data->count()) {
        return json_encode(['msg' => 'No new data in the `checkin_data` collection. Nothing to process.']);
    }
    /**
     *   Determine winners and losers from the $checkin_doc payload data.
     */
    $match_results = array_map(function ($checkin_doc) {
        $checkin = new \BarracksMaster\Checkin($checkin_doc);
        /**
         *   All checkin data should be stage 3. Stage 1/2 moved to task update_ladder_partials.
         */
        if ($checkin->getStage() == 3) {
            $winners = $checkin->getWinners();
            $losers = $checkin->getLosers();
        }
        $checkin->markAsProcessed();
        return array('_id' => $checkin_doc['_id'], 'match_id' => $checkin->matchID, 'winners' => $winners, 'losers' => $losers);
    }, iterator_to_array($fresh_checkin_data, 0));
    /**
     *   Remove match results with no winners, as results are provided for both stage 2 and stage 3.
     */
    $match_results = array_filter($match_results, function ($match_result) {
        if (empty($match_result['winners']) && empty($match_result['losers'])) {
            return false;
        } else {
            return true;
        }