<commit_before>define([
    'jquery',
    'json.sortify',
    '/common/common-util.js',
    '/common/common-hash.js',
    '/common/hyperscript.js',
    '/common/common-interface.js',
    '/customize/messages.js'
], function($, Sortify, Util, Hash, h, UI, Messages) {
    var Comments = {};

    /*
    {
        authors: {
            "id": {
                name: "",
                curvePublic: "",
                avatar: "",
                profile: ""
            }
        },
        data: {
            "uid": {
                m: [{
                    u: id,
                    m: "str", // comment
                    t: +new Date,
                    v: "str", // value of the commented content
                    e: undefined/1, // edited
                    d: undefined/1, // deleted
                }],
                d: undefined/1,
            }
        }
    }
    */

    var COMMENTS = {
        authors: {},
        data: {}
    };

    var canonicalize = function(t) { return t.replace(/\r\n/g, '\n'); };

    // XXX function duplicated from www/code/markers.js
    var authorUid = function(existing) {
        if (!Array.isArray(existing)) { existing = []; }
        var n;
        var i = 0;
        while (!n || existing.indexOf(n) !== -1 && i++ < 1000) {
            n = Math.floor(Math.random() * 1000000);
        }
        // If we can't find a valid number in 1000 iterations, use 0...
        if (existing.indexOf(n) !== -1) { n = 0; }
        return n;
    };
    var getAuthorId = function(Env, curve) {
        var existing = Object.keys(Env.comments.authors || {}).map(Number);
        if (!Env.common.isLoggedIn()) { return authorUid(existing); }

        var uid;
        existing.some(function(id) {
            var author = Env.comments.authors[id] || {};
            if (author.curvePublic !== curve) { return; }
            uid = Number(id);
            return true;
        });
        return uid || authorUid(existing);
    };

    // Return the author ID  and add/update the data for registered users
    // Return the username for unregistered users
    var updateAuthorData = function(Env, onChange) {
        var userData = Env.metadataMgr.getUserData();
        if (!Env.common.isLoggedIn()) {
            return userData.name;
        }
        var myAuthorId = getAuthorId(Env, userData.curvePublic);
        var data = Env.comments.authors[myAuthorId] = Env.comments.authors[myAuthorId] || {};
        var old = Sortify(data);
        data.name = userData.name;
        data.avatar = userData.avatar;
        data.profile = userData.profile;
        data.curvePublic = userData.curvePublic;
        data.notifications = userData.notifications;
        if (typeof(onChange) === "function" && Sortify(data) !== old) {
            onChange();
        }
        return myAuthorId;
    };

    var updateMetadata = function(Env) {
        var md = Util.clone(Env.metadataMgr.getMetadata());
        md.comments = Util.clone(Env.comments);
        Env.metadataMgr.updateMetadata(md);
    };

    var sendReplyNotification = function(Env, uid) {
        if (!Env.comments || !Env.comments.data || !Env.comments.authors) { return; }
        if (!Env.common.isLoggedIn()) { return; }
        var thread = Env.comments.data[uid];
        if (!thread || !Array.isArray(thread.m)) { return; }
        var userData = Env.metadataMgr.getUserData();
        var privateData = Env.metadataMgr.getPrivateData();
        var others = {};
        // Get all the other registered users with a mailbox
        thread.m.forEach(function(obj) {
            var u = obj.u;
            if (typeof(u) !== "number") { return; }
            var author = Env.comments.authors[u];
            if (!author || others[u] || !author.notifications || !author.curvePublic) { return; }
            if (author.curvePublic === userData.curvePublic) { return; } // don't send to yourself
            others[u] = {
                curvePublic: author.curvePublic,
                comment: obj.m,
                content: obj.v,
                notifications: author.notifications
            };
        });
        // Send the notification
        Object.keys(others).forEach(function(id) {
            var data = others[id];
            Env.common.mailbox.sendTo("COMMENT_REPLY", {
                channel: privateData.channel,
                comment: data.comment,
                content: data.content
            }, {
                channel: data.notifications,
                curvePublic: data.curvePublic
            });
        });

    };

    var cleanMentions = function($el) {
        $el.html('');
        var el = $el[0];
        var allowed = ['data-profile', 'data-name', 'data-avatar', 'class'];
        // Remove unnecessary/unsafe attributes
        for (var i = el.attributes.length - 1; i > 0; i--) {
            var name = el.attributes[i] && el.attributes[i].name;
            if (allowed.indexOf(name) === -1) {<commit_msg>Fix reply notifications with mentions<commit_after>define([
    'jquery',
    'json.sortify',
    '/common/common-util.js',
    '/common/common-hash.js',
    '/common/hyperscript.js',
    '/common/common-interface.js',
    '/customize/messages.js'
], function($, Sortify, Util, Hash, h, UI, Messages) {
    var Comments = {};

    /*
    {
        authors: {
            "id": {
                name: "",
                curvePublic: "",
                avatar: "",
                profile: ""
            }
        },
        data: {
            "uid": {
                m: [{
                    u: id,
                    m: "str", // comment
                    t: +new Date,
                    v: "str", // value of the commented content
                    e: undefined/1, // edited
                    d: undefined/1, // deleted
                }],
                d: undefined/1,
            }
        }
    }
    */

    var COMMENTS = {
        authors: {},
        data: {}
    };

    var canonicalize = function(t) { return t.replace(/\r\n/g, '\n'); };

    // XXX function duplicated from www/code/markers.js
    var authorUid = function(existing) {
        if (!Array.isArray(existing)) { existing = []; }
        var n;
        var i = 0;
        while (!n || existing.indexOf(n) !== -1 && i++ < 1000) {
            n = Math.floor(Math.random() * 1000000);
        }
        // If we can't find a valid number in 1000 iterations, use 0...
        if (existing.indexOf(n) !== -1) { n = 0; }
        return n;
    };
    var getAuthorId = function(Env, curve) {
        var existing = Object.keys(Env.comments.authors || {}).map(Number);
        if (!Env.common.isLoggedIn()) { return authorUid(existing); }

        var uid;
        existing.some(function(id) {
            var author = Env.comments.authors[id] || {};
            if (author.curvePublic !== curve) { return; }
            uid = Number(id);
            return true;
        });
        return uid || authorUid(existing);
    };

    // Return the author ID  and add/update the data for registered users
    // Return the username for unregistered users
    var updateAuthorData = function(Env, onChange) {
        var userData = Env.metadataMgr.getUserData();
        if (!Env.common.isLoggedIn()) {
            return userData.name;
        }
        var myAuthorId = getAuthorId(Env, userData.curvePublic);
        var data = Env.comments.authors[myAuthorId] = Env.comments.authors[myAuthorId] || {};
        var old = Sortify(data);
        data.name = userData.name;
        data.avatar = userData.avatar;
        data.profile = userData.profile;
        data.curvePublic = userData.curvePublic;
        data.notifications = userData.notifications;
        if (typeof(onChange) === "function" && Sortify(data) !== old) {
            onChange();
        }
        return myAuthorId;
    };

    var updateMetadata = function(Env) {
        var md = Util.clone(Env.metadataMgr.getMetadata());
        md.comments = Util.clone(Env.comments);
        Env.metadataMgr.updateMetadata(md);
    };

    var sendReplyNotification = function(Env, uid) {
        if (!Env.comments || !Env.comments.data || !Env.comments.authors) { return; }
        if (!Env.common.isLoggedIn()) { return; }
        var thread = Env.comments.data[uid];
        if (!thread || !Array.isArray(thread.m)) { return; }
        var userData = Env.metadataMgr.getUserData();
        var privateData = Env.metadataMgr.getPrivateData();
        var others = {};
        // Get all the other registered users with a mailbox
        thread.m.forEach(function(obj) {
            var u = obj.u;
            if (typeof(u) !== "number") { return; }
            var author = Env.comments.authors[u];
            if (!author || others[u] || !author.notifications || !author.curvePublic) { return; }
            if (author.curvePublic === userData.curvePublic) { return; } // don't send to yourself
            others[u] = {
                curvePublic: author.curvePublic,
                comment: obj.m,
                content: obj.v,
                notifications: author.notifications
            };
        });
        // Send the notification
        Object.keys(others).forEach(function(id) {
            var data = others[id];
            Env.common.mailbox.sendTo("COMMENT_REPLY", {
                channel: privateData.channel,
                comment: data.comment.replace(/<[^>]*>/g, ''),
                content: data.content
            }, {
                channel: data.notifications,
                curvePublic: data.curvePublic
            });
        });

    };

    var cleanMentions = function($el) {
        $el.html('');
        var el = $el[0];
        var allowed = ['data-profile', 'data-name', 'data-avatar', 'class'];
        // Remove unnecessary/unsafe attributes
        for (var i = el.attributes.length - 1; i > 0; i--) {
            var name = el.attributes[i] && el.attributes[i].name;
            if (allowed.indexOf(name) === -1) {
{'fraction_non_alphanumeric': 0.1410667736113896, 'fraction_numerical': 0.0054140765991578105, 'mean_word_length': 1.6663993584603047, 'pattern_counts': {'":': 4, '<': 6, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '4584109', 'n_tokens_mistral': 2917, 'n_tokens_neox': 2785, 'n_words': 638}