<commit_before>var activity = (function () {
var exports = {};

/*
    Helpers for detecting user activity and managing user idle states
*/

/* Broadcast "idle" to server after 5 minutes of local inactivity */
var DEFAULT_IDLE_TIMEOUT_MS = 5 * 60 * 1000;
/* Time between keep-alive pings */
var ACTIVE_PING_INTERVAL_MS = 50 * 1000;

/* Mark users as offline after 140 seconds since their last checkin,
 * Keep in sync with zerver/tornado/event_queue.py:receiver_is_idle
 */
var OFFLINE_THRESHOLD_SECS = 140;

// Testing
exports._OFFLINE_THRESHOLD_SECS = OFFLINE_THRESHOLD_SECS;

var MOBILE_DEVICES = ["Android", "ZulipiOS", "ios"];

function is_mobile(device) {
    return MOBILE_DEVICES.indexOf(device) !== -1;
}

var presence_descriptions = {
    active: 'is active',
    idle:   'is not active',
};

/* Keep in sync with views.py:update_active_status_backend() */
exports.ACTIVE = "active";
exports.IDLE = "idle";

// When you start Zulip, has_focus should be true, but it might not be the
// case after a server-initiated reload.
exports.has_focus = document.hasFocus && document.hasFocus();

// We initialize this to true, to count new page loads, but set it to
// false in the onload function in reload.js if this was a
// server-initiated-reload to avoid counting a server-initiated reload
// as user activity.
exports.new_user_input = true;

$("html").on("mousemove", function () {
    exports.new_user_input = true;
});

exports.presence_info = {};

var huddle_timestamps = new Dict();

function update_count_in_dom(count_span, value_span, count) {
    if (count === 0) {
        count_span.hide();
        if (count_span.parent().hasClass("user_sidebar_entry")) {
            count_span.parent(".user_sidebar_entry").removeClass("user-with-count");
        } else if (count_span.parent().hasClass("group-pms-sidebar-entry")) {
            count_span.parent(".group-pms-sidebar-entry").removeClass("group-with-count");
        }
        value_span.text('');
        return;
    }

    count_span.show();

    if (count_span.parent().hasClass("user_sidebar_entry")) {
        count_span.parent(".user_sidebar_entry").addClass("user-with-count");
    } else if (count_span.parent().hasClass("group-pms-sidebar-entry")) {
        count_span.parent(".group-pms-sidebar-entry").addClass("group-with-count");
    }
    value_span.text(count);
}

function get_filter_li(user_ids_string) {
    if (name.indexOf(",") < 0) {
        return $("li.user_sidebar_entry[data-user-id='" + user_ids_string + "']");
    }
    return $("li.group-pms-sidebar-entry[data-user-ids='" + user_ids_string + "']");
}

function set_count(user_ids_string, count) {
    var count_span = get_filter_li(user_ids_string).find('.count');
    var value_span = count_span.find('.value');
    update_count_in_dom(count_span, value_span, count);
}

exports.update_dom_with_unread_counts = function (counts) {
    // counts is just a data object that gets calculated elsewhere
    // Our job is to update some DOM elements.

    counts.pm_count.each(function (count, user_ids_string) {
        // TODO: just use user_ids_string in our markup
        set_count(user_ids_string, count);
    });
};

exports.process_loaded_messages = function (messages) {
    var need_resize = false;

    _.each(messages, function (message) {
        var huddle_string = people.huddle_string(message);

        if (huddle_string) {
            var old_timestamp = huddle_timestamps.get(huddle_string);

            if (!old_timestamp || (old_timestamp < message.timestamp)) {
                huddle_timestamps.set(huddle_string, message.timestamp);
                need_resize = true;
            }
        }
    });

    exports.update_huddles();

    if (need_resize) {
        resize.resize_page_components(); // big hammer
    }
};

exports.get_huddles = function () {
    var huddles = huddle_timestamps.keys();
    huddles = _.sortBy(huddles, function (huddle) {
        return huddle_timestamps.get(huddle);
    });
    return huddles.reverse();
};

exports.full_huddle_name = function (huddle) {
    var user_ids = huddle.split(',');

    var names = _.map(user_ids, function (user_id) {
        var person = people.get_person_from_user_id(user_id);
        return person.full_name;
    });

    return names.join(', ');
};

exports.short_huddle_name = function (huddle) {
    var user_ids = huddle.split(',');

    var num_to_show = 3;
    var names = _.map(user_ids, function (user_id) {
        var person = people.get_person_from_user_id(user_id);
        return person.full_name;
    });

    names = _.sortBy(names, function (name) { return name.toLowerCase(); });
    names = names.slice(0, num_to_show);
    var others = user_ids.length - num_to_show;

    if (others === 1) {
        names.push("+ 1 other");
    } else if (others >= 2) {
        names.push("+ " + others + " others");
    }

    return names.join(', ');
};

exports.huddle_fraction_present = function (huddle) {
    var presence_info = exports.presence_info;
    var user_ids = huddle.split(',');

    var num_present = 0;
    _.each(user_ids, function (user_id) {
        if (presence_info[user_id]) {
            var status = presence_info[user_id].status;
            if (status && (status !== 'offline')) {
                num_present += 1;
            }
        }
    });

    var ratio = num_present / user_ids.length;

    return ratio.toFixed(2);
};

function compare_function(a, b) {
    var presence_info = exports.presence_info;

    if (presence_info[a].status === 'active' && presence_info[b].status !== 'active') {
        return -1;
    } else if (presence_info[b].status === 'active' && presence_info[a].status !== 'active') {
        return 1;
    }

    if (presence_info[a].status === 'idle' && presence_info[b].status !== 'idle') {
        return -1;
    } else if (presence_info[b].status === 'idle' && presence_info[a].status !== 'idle') {
        return 1;
    }

    // Sort equivalent PM names alphabetically
    var person_a = people.get_person_from_user_id(a);
    var person_b = people.get_person_from_user_id(b);

    var full_name_a = person_a ? person_a.full_name : '';
    var full_name_b = person_b ? person_b.full_name : '';

    return util.strcmp(full_name_a, full_name_b);
}

function sort_users(user_ids) {
    // TODO sort by unread count first, once we support that<commit_msg>Simplify buddy list status level sorting.<commit_after>var activity = (function () {
var exports = {};

/*
    Helpers for detecting user activity and managing user idle states
*/

/* Broadcast "idle" to server after 5 minutes of local inactivity */
var DEFAULT_IDLE_TIMEOUT_MS = 5 * 60 * 1000;
/* Time between keep-alive pings */
var ACTIVE_PING_INTERVAL_MS = 50 * 1000;

/* Mark users as offline after 140 seconds since their last checkin,
 * Keep in sync with zerver/tornado/event_queue.py:receiver_is_idle
 */
var OFFLINE_THRESHOLD_SECS = 140;

// Testing
exports._OFFLINE_THRESHOLD_SECS = OFFLINE_THRESHOLD_SECS;

var MOBILE_DEVICES = ["Android", "ZulipiOS", "ios"];

function is_mobile(device) {
    return MOBILE_DEVICES.indexOf(device) !== -1;
}

var presence_descriptions = {
    active: 'is active',
    idle:   'is not active',
};

/* Keep in sync with views.py:update_active_status_backend() */
exports.ACTIVE = "active";
exports.IDLE = "idle";

// When you start Zulip, has_focus should be true, but it might not be the
// case after a server-initiated reload.
exports.has_focus = document.hasFocus && document.hasFocus();

// We initialize this to true, to count new page loads, but set it to
// false in the onload function in reload.js if this was a
// server-initiated-reload to avoid counting a server-initiated reload
// as user activity.
exports.new_user_input = true;

$("html").on("mousemove", function () {
    exports.new_user_input = true;
});

exports.presence_info = {};

var huddle_timestamps = new Dict();

function update_count_in_dom(count_span, value_span, count) {
    if (count === 0) {
        count_span.hide();
        if (count_span.parent().hasClass("user_sidebar_entry")) {
            count_span.parent(".user_sidebar_entry").removeClass("user-with-count");
        } else if (count_span.parent().hasClass("group-pms-sidebar-entry")) {
            count_span.parent(".group-pms-sidebar-entry").removeClass("group-with-count");
        }
        value_span.text('');
        return;
    }

    count_span.show();

    if (count_span.parent().hasClass("user_sidebar_entry")) {
        count_span.parent(".user_sidebar_entry").addClass("user-with-count");
    } else if (count_span.parent().hasClass("group-pms-sidebar-entry")) {
        count_span.parent(".group-pms-sidebar-entry").addClass("group-with-count");
    }
    value_span.text(count);
}

function get_filter_li(user_ids_string) {
    if (name.indexOf(",") < 0) {
        return $("li.user_sidebar_entry[data-user-id='" + user_ids_string + "']");
    }
    return $("li.group-pms-sidebar-entry[data-user-ids='" + user_ids_string + "']");
}

function set_count(user_ids_string, count) {
    var count_span = get_filter_li(user_ids_string).find('.count');
    var value_span = count_span.find('.value');
    update_count_in_dom(count_span, value_span, count);
}

exports.update_dom_with_unread_counts = function (counts) {
    // counts is just a data object that gets calculated elsewhere
    // Our job is to update some DOM elements.

    counts.pm_count.each(function (count, user_ids_string) {
        // TODO: just use user_ids_string in our markup
        set_count(user_ids_string, count);
    });
};

exports.process_loaded_messages = function (messages) {
    var need_resize = false;

    _.each(messages, function (message) {
        var huddle_string = people.huddle_string(message);

        if (huddle_string) {
            var old_timestamp = huddle_timestamps.get(huddle_string);

            if (!old_timestamp || (old_timestamp < message.timestamp)) {
                huddle_timestamps.set(huddle_string, message.timestamp);
                need_resize = true;
            }
        }
    });

    exports.update_huddles();

    if (need_resize) {
        resize.resize_page_components(); // big hammer
    }
};

exports.get_huddles = function () {
    var huddles = huddle_timestamps.keys();
    huddles = _.sortBy(huddles, function (huddle) {
        return huddle_timestamps.get(huddle);
    });
    return huddles.reverse();
};

exports.full_huddle_name = function (huddle) {
    var user_ids = huddle.split(',');

    var names = _.map(user_ids, function (user_id) {
        var person = people.get_person_from_user_id(user_id);
        return person.full_name;
    });

    return names.join(', ');
};

exports.short_huddle_name = function (huddle) {
    var user_ids = huddle.split(',');

    var num_to_show = 3;
    var names = _.map(user_ids, function (user_id) {
        var person = people.get_person_from_user_id(user_id);
        return person.full_name;
    });

    names = _.sortBy(names, function (name) { return name.toLowerCase(); });
    names = names.slice(0, num_to_show);
    var others = user_ids.length - num_to_show;

    if (others === 1) {
        names.push("+ 1 other");
    } else if (others >= 2) {
        names.push("+ " + others + " others");
    }

    return names.join(', ');
};

exports.huddle_fraction_present = function (huddle) {
    var presence_info = exports.presence_info;
    var user_ids = huddle.split(',');

    var num_present = 0;
    _.each(user_ids, function (user_id) {
        if (presence_info[user_id]) {
            var status = presence_info[user_id].status;
            if (status && (status !== 'offline')) {
                num_present += 1;
            }
        }
    });

    var ratio = num_present / user_ids.length;

    return ratio.toFixed(2);
};

function compare_function(a, b) {
    var presence_info = exports.presence_info;

    function level(status) {
        switch (status) {
            case 'active':
                return 1;
            case 'idle':
                return 2;
            default:
                return 3;
        }
    }

    var level_a = level(presence_info[a].status);
    var level_b = level(presence_info[b].status);
    var diff = level_a - level_b;
    if (diff !== 0) {
        return diff;
    }

    // Sort equivalent PM names alphabetically
    var person_a = people.get_person_from_user_id(a);
    var person_b = people.get_person_from_user_id(b);

    var full_name_a = person_a ? person_a.full_name : '';
    var full_name_b = person_b ? person_b.full_name : '';

    return util.strcmp(full_name_a, full_name_b);
}

function sort_users(user_ids) {
    // TODO sort by unread count first, once we support that
{'fraction_non_alphanumeric': 0.13150641782817546, 'fraction_numerical': 0.005512245058666037, 'mean_word_length': 3.0901771336553945, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, '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': '5793198', 'n_tokens_mistral': 4256, 'n_tokens_neox': 4102, 'n_words': 902}