<commit_before>// Tracks global metadata for a file in the review, not tied to any iteration
define([], function () {
    'use strict';

    const proto = {
        is: function (otherUser) {
            return otherUser
                && Object.getPrototypeOf(otherUser) === proto
                && otherUser.email.toLocaleLowerCase() === this.email.toLocaleLowerCase();
        },

        toString: function () {
            return `${this.name} <${this.email}>`.trim();
        },

        getAvatarUrl: function (size) {
            return `http://www.gravatar.com/avatar/${SparkMD5.hash(this.email.toLowerCase())}?s=${size || 28}&d=retro`;
        }
    };

    function User(displayName, email) {
        const obj = Object.create(proto);
        obj.name = displayName.trim();
        obj.email = email.trim();
        return obj;
    }

    User.parse = function (str) {
        const parts = /\s*([^<]*?)\s*<(([^@]+).+)>\s*$/.exec(str);
        const name = parts && (parts[1] || parts[3]) || 'NAME_MISSING';
        const email = parts && parts[2] || 'EMAIL_MISSING';

        return User(name.trim(), email.trim());
    };

    return User;
});<commit_msg>added extended email parsing and detection to User<commit_after>// Tracks global metadata for a file in the review, not tied to any iteration
define([], function () {
    'use strict';

    const proto = {
        is: function (otherUser) {
            return otherUser
                && Object.getPrototypeOf(otherUser) === proto
                && otherUser.email.toLocaleLowerCase() === this.email.toLocaleLowerCase();
        },

        toString: function () {
            return `${this.name} <${this.email}>`.trim();
        },

        getAvatarUrl: function (size) {
            return `http://www.gravatar.com/avatar/${SparkMD5.hash(this.email.toLowerCase())}?s=${size || 28}&d=retro`;
        }
    };

    function User(displayName, email) {
        const obj = Object.create(proto);
        if (!displayName || typeof displayName !== 'string') {
            throw new Error('Email address string is required at minimum to construct a user');
        } else  if (displayName && email) {
            obj.name = displayName.trim();
            obj.email = email.trim();
        } else if (proto.isPrototypeOf(displayName)) {
            return displayName;
        } else if (displayName.indexOf('@') >= 0) {
            const tryParse = User.parse(displayName);
            if (tryParse.email !== 'EMAIL_MISSING') {
                return tryParse;
            } else {
                obj.name = '';
                obj.email = displayName.trim();
            }
        } else {
            throw new Error("Cannot parse as user: " + displayName)
        }
        return obj;
    }

    User.parse = function (str) {
        const parts = /\s*([^<]*?)\s*<(([^@]+).+)>\s*$/.exec(str);
        const name = parts && (parts[1] || parts[3]) || 'NAME_MISSING';
        const email = parts && parts[2] || 'EMAIL_MISSING';

        return User(name.trim(), email.trim());
    };

    return User;
});
{'fraction_non_alphanumeric': 0.16184595385115372, 'fraction_numerical': 0.004224894377640559, 'mean_word_length': 2.07185628742515, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 8, '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': '862000', 'n_tokens_mistral': 907, 'n_tokens_neox': 881, 'n_words': 208}