$retVal = 0;
    $query = 'SELECT round_id FROM round WHERE round_character1_id = :id OR round_character2_id = :id';
    $result = Lib\Db::Query('SELECT COUNT(1) AS total, SUM(CASE WHEN character_id = :id THEN 1 ELSE 0 END) AS character_votes FROM votes WHERE round_id IN (' . $query . ') AND user_id IN (' . implode(',', $users) . ')', [':id' => $char->id]);
    if ($result && $result->count) {
        $row = Lib\Db::Fetch($result);
        $retVal = (int) $row->character_votes / (int) $row->total;
    }
    return $retVal;
}
$projections = [];
// Get the current voting round
$rounds = Api\Round::getCurrentRounds(AI_BRACKET_ID);
foreach ($rounds as $round) {
    // Data gathering
    $char1 = Api\Character::getById($round->character1Id);
    $char2 = Api\Character::getById($round->character2Id);
    $nonLoyalists = getNonLoyalists($char1, $char2);
    $char1->loyalists = getLoyalists($char1, $char2);
    $char2->loyalists = getLoyalists($char2, $char1);
    $char1->sourceStrength = getSourceStrength($char1, $nonLoyalists);
    $char2->sourceStrength = getSourceStrength($char2, $nonLoyalists);
    $char1->percentOfTimesVotedFor = getPercentTimesVotedFor($char1, $nonLoyalists);
    $char2->percentOfTimesVotedFor = getPercentTimesVotedFor($char2, $nonLoyalists);
    // Below is the scientific explanation as penned by Chris Hackmann
    // The percentage of voters who are not loyal to one character or the other
    $nonLoyalistPercentage = 1 - ($char1->loyalists->percent + $char2->loyalists->percent);
    // Determine which character is voted for more often overall
    $bestCharacter = $char1->percentOfTimesVotedFor > $char2->percentOfTimesVotedFor ? $char1 : $char2;
    $worstCharacter = $char1->percentOfTimesVotedFor > $char2->percentOfTimesVotedFor ? $char2 : $char1;
    // The popularity ration represents how many votes the best character gets for each vote for the worst character
    $popularityRatio = $bestCharacter->percentOfTimesVotedFor / $worstCharacter->percentOfTimesVotedFor;
<?php

require 'lib/aal.php';
$db = Lib\Mongo::getDatabase();
$characterRankingInfo = $db->characterRankingInfo;
$result = Lib\Db::Query('SELECT * FROM `character` WHERE bracket_id = 6 AND (SELECT COUNT(1) FROM round WHERE round_tier > 0 AND (round_character1_id = character_id OR round_character2_id = character_id)) > 0');
while ($row = Lib\Db::Fetch($result)) {
    $character = new Api\Character($row);
    echo $character->name, '...';
    $obj = new stdClass();
    $obj->characterId = (int) $character->id;
    $obj->performance = round($character->getAverageRoundPerformance(true) * 100);
    $obj->alsoVotedFor = $character->getCharactersAlsoVotedFor(false, true);
    $obj->sameSourceVotes = $character->getCharactersAlsoVotedFor(true, true);
    // JSON encode/decode the object to strip private keys
    $obj = json_decode(json_encode($obj));
    // Check for this character in the collection so we can update the existing record. This is intentionally
    // done after the JSON bullshit above to make sure the object is correctly represented
    $record = $characterRankingInfo->findOne(['characterId' => $character->id]);
    if ($record) {
        $obj->_id = $record['_id'];
    }
    $characterRankingInfo->save($obj);
    echo 'DONE', PHP_EOL;
}