<commit_before>$(function() {
    var session = {
        loggedIn: false,
        userName: '',
        password: '',
        id: 0,
    };
    // TODO: channel page state (dirty)
    var viewStates = {};
    function getViewState() {
        if (!viewStates[session.id]) {
            viewStates[session.id] = {
                stream: null,
                streamContinuingErrorNum: 0,
                channels: [],
                channelName: '',
                newMessages: {},
                messageIdsAlreadyShown: {},
                userNames: {},
            }
        }
        return viewStates[session.id];
    }
    function isSameArray(a, b, func) {
        if (!func) {
            func = function (x, y) {
                return x === y;
            };
        }
        if (a.length !== b.length) {
            return false;
        }
        for (var i = 0; i < a.length; i++) {
            if (!func(a[i], b[i])) {
                return false;
            }
        }
        return true;
    }
    function uniq(arr) {
        var values = {};
        for (var i = 0; i < arr.length; i++) {
            values[arr[i]] = true;
        }
        return Object.keys(values);
    }
    var updateViewChannels = (function () {
        var cachedChannels = [];
        return function () {
            // channels
            var viewState = getViewState();
            var channels = viewState.channels.sort(function (a, b) {
                if (a.name > b.name) {
                    return 1;
                }
                if (a.name < b.name) {
                    return -1;
                }
                return 0;
            });
            if (isSameArray(channels, cachedChannels)) {
                return;
            }
            var ul = $('#channels ul');
            ul.empty();
            $.each(channels, function (i, channel) {
                var a = $('<a href="#"></a>');
                a.text(channel.name);
                a.click(function () {
                    viewState.channelName = channel.name;
                    if (!viewState.userNames[viewState.channelName]) {
                        updateUserList();
                    }
                    updateView();
                    return false;
                });
                var li = $('<li></li>');
                li.append(a);
                ul.append(li);
            });
            cachedChannels = [];
            for (var i = 0; i < channels.length; i++) {
                cachedChannels[i] = channels[i];
            }
        }
    })();
    function updateViewMessages() {
        var viewState = getViewState();
        if (viewState.channelName) {
            $('#messages h2').text(viewState.channelName);
        } else {
            $('#messages h2').text("\u00a0");
        }
        /*$('#messages > section').filter(function (i) {
          var channelName = $(this).attr('data-channel-name');
          return // TODO: implement
          }).remove();*/
        if (viewState.channelName &&
            $('#messages > section').filter(function (i) {
                return $(this).attr('data-channel-name') === viewState.channelName;
            }).length === 0) {
            var section = $('<section></section>');
            section.attr('data-channel-name', viewState.channelName);
            $('#messages h2').after(section);
        }
        $('#messages > section').each(function (i) {
            var e = $(this);
            if (e.attr('data-channel-name') === viewState.channelName) {
                e.show();
            } else {
                e.hide();
            }
        });
        if (!viewState.channelName) {
            return;
        }
        function messageToElement(message) {
            var messageSection = $('<section></section>');
            messageSection.addClass('message');
            var userNameP = $('<p></p>').text(message.user_name);
            userNameP.addClass('userName');
            messageSection.append(userNameP);
            var bodyP = $('<p></p>').text(message.body);
            bodyP.addClass('body');
            messageSection.append(bodyP);
            // TODO: Use the element <time>?
            var time = new Date();
            time.setTime(message.created_at * 1000);
            var h = time.getHours() + '';
            var m = time.getMinutes() + '';
            if (h.length < 2) {
                h = '0' + h;
            }
            if (m.length < 2) {
                m = '0' + m;
            }
            var timeStr = h + ':' + m;
            var createdAtP = $('<p></p>').text(timeStr);
            createdAtP.addClass('createdAt');
            messageSection.append(createdAtP);
            messageSection.attr('data-message-id', message.id);
            return messageSection;
        }
        var msgs = viewState.newMessages[viewState.channelName];
        if (!msgs) {
            msgs = [];
        }
        var section = $('#messages > section').filter(function (i) {
            return $(this).attr('data-channel-name') === viewState.channelName;
        });
        var isBottom =
            section.get(0).scrollHeight - section.scrollTop() ===
            section.outerHeight();
        // TODO: sort by id
        $.each(msgs, function (i, message) {
            if (viewState.messageIdsAlreadyShown[message.id]) {
                return;
            }
            section.append(messageToElement(message));
            viewState.messageIdsAlreadyShown[message.id] = true;
        });
        if (isBottom) {
            section.animate({scrollTop: section.get(0).scrollHeight});
        }
        viewState.newMessages[viewState.channelName] = [];
    }
    function updateViewUsers() {
        var viewState = getViewState();
        var userNames = viewState.userNames[viewState.channelName];
        if (!userNames) {
            userNames = [];
        }
        var userNames = userNames.sort();
        var ul = $('#users ul');
        ul.empty();
        $.each(userNames, function (i, userName) {
            var li = $('<li></li>');
            li.text(userName);
            ul.append(li);
        });
    }
    function updateView() {
        if (session.loggedIn) {
            $('#logInForm').hide();
            $('#logOutLink span').text(session.userName);
            $('#logOutLink').show();
            $('#main input').removeAttr('disabled');
            if (getViewState().channelName) {
                $('#postMessageForm input').removeAttr('disabled');
            } else {
                $('#postMessageForm input').attr('disabled', 'disabled');
            }
        } else {
            $('#logInForm').show();
            $('#logOutLink').hide();
            $('#main input').attr('disabled', 'disabled');
        }
        updateViewChannels();
        updateViewMessages();
        updateViewUsers();
    };
    function startStream() {
        var viewState = getViewState();
        if (viewState.stream) {
            viewState.stream.abort();
        }
        viewState.stream = null;
        var i = 0;
        viewState.stream = $.ajax({
            url: '/users/' + encodeURIComponent(session.userName) +
                '/stream',
            type: 'GET',
            cache: false,
            beforeSend: addAuthHeader,
            xhrFields: {
                onprogress: function () {
                    // TODO: Reconnecting if overflow
                    var xhr = this;
                    var text = xhr.responseText;
                    var subText = text.substring(i);
                    while (true) {
                        var tokenLength = subText.search("\n");
                        if (tokenLength === -1) {
                            break;
                        }
                        i += tokenLength + 1;
                        var token = subText.substring(0, tokenLength);
                        subText = subText.substring(tokenLength + 1);
                        try {
                            var obj = JSON.parse(token);
                        } catch (e) {
                            console.log(e);
                            continue;
                        }
                        if (obj.type === 'message') {
                            var channelName = obj.channel_name;
                            var message = obj.message;
                            if (channelName && message) {
                                if (!viewState.newMessages[channelName]) {
                                    viewState.newMessages[channelName] = [];
                                }
                                viewState.newMessages[channelName].push(message);
                                if (channelName === getViewState().channelName) {
                                    updateView();
                                }
                            }
                        } else if (obj.type === 'subscribing') {
                            var channelName = obj.channel_name;
                            // TODO: update viewState.channels
                            if (!viewState.userNames[channelName]) {
                                viewState.userNames[channelName] = [];
                            }
                            var userNames = viewState.userNames[channelName];
                            userNames.push(obj.user_name);
                            viewState.userNames[channelName] = uniq(userNames);
                            // TODO: bug fix
                            if (channelName === getViewState().channelName) {
                                updateView();
                            }
                        }
                    }
                },
            },
            success: function (data, textStatus, jqXHR) {
                viewState.streamContinuingErrorNum = 0;
                setTimeout(startStream, 0);
            },
            error: function (jqXHR, textStatus, errorThrown) {
                console.log(textStatus);
                viewState.streamContinuingErrorNum++;
                if (10 <= viewState.streamContinuingErrorNum) {
                    console.log('Too many errors!');
                    // TODO: implement showing error message
                    return;
                }
                setTimeout(startStream, 10000);
            },
        });
    }
    function stopStream() {
        var viewState = getViewState();
        if (viewState.stream) {
            viewState.stream.abort();
        }
        viewState.stream = null;
        viewState.streamContinuingErrorNum = 0;
    }
    function logIn(userName, password) {
        localStorage.userName = userName;
        localStorage.password = password;
        session.loggedIn = true;
        session.userName = userName;
        session.password = password;
        session.id = (new Date()).getTime();
        updateChannelList();
        updateView();
        startStream();
    }
    function logOut() {
        delete localStorage.userName;
        delete localStorage.password;
        session.loggedIn = false;
        session.userName = '';
        session.password = '';
        session.id = 0;
        $('#messages > section').remove();<commit_msg>Remove viewState when logging out<commit_after>$(function() {
    var session = {
        loggedIn: false,
        userName: '',
        password: '',
        id: 0,
    };
    // TODO: channel page state (dirty)
    var viewStates = {};
    function getViewState() {
        if (!viewStates[session.id]) {
            viewStates[session.id] = {
                stream: null,
                streamContinuingErrorNum: 0,
                channels: [],
                channelName: '',
                newMessages: {},
                messageIdsAlreadyShown: {},
                userNames: {},
            }
        }
        return viewStates[session.id];
    }
    function isSameArray(a, b, func) {
        if (!func) {
            func = function (x, y) {
                return x === y;
            };
        }
        if (a.length !== b.length) {
            return false;
        }
        for (var i = 0; i < a.length; i++) {
            if (!func(a[i], b[i])) {
                return false;
            }
        }
        return true;
    }
    function uniq(arr) {
        var values = {};
        for (var i = 0; i < arr.length; i++) {
            values[arr[i]] = true;
        }
        return Object.keys(values);
    }
    var updateViewChannels = (function () {
        var cachedChannels = [];
        return function () {
            // channels
            var viewState = getViewState();
            var channels = viewState.channels.sort(function (a, b) {
                if (a.name > b.name) {
                    return 1;
                }
                if (a.name < b.name) {
                    return -1;
                }
                return 0;
            });
            if (isSameArray(channels, cachedChannels)) {
                return;
            }
            var ul = $('#channels ul');
            ul.empty();
            $.each(channels, function (i, channel) {
                var a = $('<a href="#"></a>');
                a.text(channel.name);
                a.click(function () {
                    viewState.channelName = channel.name;
                    if (!viewState.userNames[viewState.channelName]) {
                        updateUserList();
                    }
                    updateView();
                    return false;
                });
                var li = $('<li></li>');
                li.append(a);
                ul.append(li);
            });
            cachedChannels = [];
            for (var i = 0; i < channels.length; i++) {
                cachedChannels[i] = channels[i];
            }
        }
    })();
    function updateViewMessages() {
        var viewState = getViewState();
        if (viewState.channelName) {
            $('#messages h2').text(viewState.channelName);
        } else {
            $('#messages h2').text("\u00a0");
        }
        /*$('#messages > section').filter(function (i) {
          var channelName = $(this).attr('data-channel-name');
          return // TODO: implement
          }).remove();*/
        if (viewState.channelName &&
            $('#messages > section').filter(function (i) {
                return $(this).attr('data-channel-name') === viewState.channelName;
            }).length === 0) {
            var section = $('<section></section>');
            section.attr('data-channel-name', viewState.channelName);
            $('#messages h2').after(section);
        }
        $('#messages > section').each(function (i) {
            var e = $(this);
            if (e.attr('data-channel-name') === viewState.channelName) {
                e.show();
            } else {
                e.hide();
            }
        });
        if (!viewState.channelName) {
            return;
        }
        function messageToElement(message) {
            var messageSection = $('<section></section>');
            messageSection.addClass('message');
            var userNameP = $('<p></p>').text(message.user_name);
            userNameP.addClass('userName');
            messageSection.append(userNameP);
            var bodyP = $('<p></p>').text(message.body);
            bodyP.addClass('body');
            messageSection.append(bodyP);
            // TODO: Use the element <time>?
            var time = new Date();
            time.setTime(message.created_at * 1000);
            var h = time.getHours() + '';
            var m = time.getMinutes() + '';
            if (h.length < 2) {
                h = '0' + h;
            }
            if (m.length < 2) {
                m = '0' + m;
            }
            var timeStr = h + ':' + m;
            var createdAtP = $('<p></p>').text(timeStr);
            createdAtP.addClass('createdAt');
            messageSection.append(createdAtP);
            messageSection.attr('data-message-id', message.id);
            return messageSection;
        }
        var msgs = viewState.newMessages[viewState.channelName];
        if (!msgs) {
            msgs = [];
        }
        var section = $('#messages > section').filter(function (i) {
            return $(this).attr('data-channel-name') === viewState.channelName;
        });
        var isBottom =
            section.get(0).scrollHeight - section.scrollTop() ===
            section.outerHeight();
        // TODO: sort by id
        $.each(msgs, function (i, message) {
            if (viewState.messageIdsAlreadyShown[message.id]) {
                return;
            }
            section.append(messageToElement(message));
            viewState.messageIdsAlreadyShown[message.id] = true;
        });
        if (isBottom) {
            section.animate({scrollTop: section.get(0).scrollHeight});
        }
        viewState.newMessages[viewState.channelName] = [];
    }
    function updateViewUsers() {
        var viewState = getViewState();
        var userNames = viewState.userNames[viewState.channelName];
        if (!userNames) {
            userNames = [];
        }
        var userNames = userNames.sort();
        var ul = $('#users ul');
        ul.empty();
        $.each(userNames, function (i, userName) {
            var li = $('<li></li>');
            li.text(userName);
            ul.append(li);
        });
    }
    function updateView() {
        if (session.loggedIn) {
            $('#logInForm').hide();
            $('#logOutLink span').text(session.userName);
            $('#logOutLink').show();
            $('#main input').removeAttr('disabled');
            if (getViewState().channelName) {
                $('#postMessageForm input').removeAttr('disabled');
            } else {
                $('#postMessageForm input').attr('disabled', 'disabled');
            }
        } else {
            $('#logInForm').show();
            $('#logOutLink').hide();
            $('#main input').attr('disabled', 'disabled');
        }
        updateViewChannels();
        updateViewMessages();
        updateViewUsers();
    };
    function startStream() {
        var viewState = getViewState();
        if (viewState.stream) {
            viewState.stream.abort();
        }
        viewState.stream = null;
        var i = 0;
        viewState.stream = $.ajax({
            url: '/users/' + encodeURIComponent(session.userName) +
                '/stream',
            type: 'GET',
            cache: false,
            beforeSend: addAuthHeader,
            xhrFields: {
                onprogress: function () {
                    // TODO: Reconnecting if overflow
                    var xhr = this;
                    var text = xhr.responseText;
                    var subText = text.substring(i);
                    while (true) {
                        var tokenLength = subText.search("\n");
                        if (tokenLength === -1) {
                            break;
                        }
                        i += tokenLength + 1;
                        var token = subText.substring(0, tokenLength);
                        subText = subText.substring(tokenLength + 1);
                        try {
                            var obj = JSON.parse(token);
                        } catch (e) {
                            console.log(e);
                            continue;
                        }
                        if (obj.type === 'message') {
                            var channelName = obj.channel_name;
                            var message = obj.message;
                            if (channelName && message) {
                                if (!viewState.newMessages[channelName]) {
                                    viewState.newMessages[channelName] = [];
                                }
                                viewState.newMessages[channelName].push(message);
                                if (channelName === getViewState().channelName) {
                                    updateView();
                                }
                            }
                        } else if (obj.type === 'subscribing') {
                            var channelName = obj.channel_name;
                            // TODO: update viewState.channels
                            if (!viewState.userNames[channelName]) {
                                viewState.userNames[channelName] = [];
                            }
                            var userNames = viewState.userNames[channelName];
                            userNames.push(obj.user_name);
                            viewState.userNames[channelName] = uniq(userNames);
                            // TODO: bug fix
                            if (channelName === getViewState().channelName) {
                                updateView();
                            }
                        }
                    }
                },
            },
            success: function (data, textStatus, jqXHR) {
                viewState.streamContinuingErrorNum = 0;
                setTimeout(startStream, 0);
            },
            error: function (jqXHR, textStatus, errorThrown) {
                console.log(textStatus);
                viewState.streamContinuingErrorNum++;
                if (10 <= viewState.streamContinuingErrorNum) {
                    console.log('Too many errors!');
                    // TODO: implement showing error message
                    return;
                }
                setTimeout(startStream, 10000);
            },
        });
    }
    function stopStream() {
        var viewState = getViewState();
        if (viewState.stream) {
            viewState.stream.abort();
        }
        viewState.stream = null;
        viewState.streamContinuingErrorNum = 0;
    }
    function logIn(userName, password) {
        localStorage.userName = userName;
        localStorage.password = password;
        session.loggedIn = true;
        session.userName = userName;
        session.password = password;
        session.id = (new Date()).getTime();
        updateChannelList();
        updateView();
        startStream();
    }
    function logOut() {
        delete localStorage.userName;
        delete localStorage.password;
        session.loggedIn = false;
        session.userName = '';
        session.password = '';
        if (session.id !== 0) {
            delete viewStates[session.id];
        }
        session.id = 0;
        $('#messages > section').remove();
{'fraction_non_alphanumeric': 0.12777064991372827, 'fraction_numerical': 0.0036720789275759857, 'mean_word_length': 1.2223970111100186, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '340113', 'n_tokens_mistral': 5723, 'n_tokens_neox': 5545, 'n_words': 1094}