<commit_before>// ------------------------------------------------------------------------------------------------------------- //
// no.events
// ------------------------------------------------------------------------------------------------------------- //

no.events = {};

// ------------------------------------------------------------------------------------------------------------- //

/**
    Тип для обработчиков событий.
    @typedef {function(string, *=)}
*/
no.events.type_handler;

// ------------------------------------------------------------------------------------------------------------- //

/**
    Внутренний кэш обработчиков событий.
    @type {Object.<string, Array.<no.events.type_handler>>}
*/
no.events._handlers = {};

/**
    @type {number}
*/
no.events._hid = 1;

/**
    @type {string}
    @const
*/
no.events._expando = '__events' + (+new Date());

// ------------------------------------------------------------------------------------------------------------- //

/**
    Возвращает список обработчиков события name.
    Если еще ни одного обработчика не забинжено, возвращает (и сохраняет) пустой список.

    @param {string} name
    @return {Array.<no.events.type_handler>}
*/
no.events._get = function(name) {
    var handlers = no.events._handlers[name];
    if (!handlers) {
        handlers = no.events._handlers[name] = [];
    }
    return handlers;
};

// ------------------------------------------------------------------------------------------------------------- //

/**
    Подписываем обработчик handler на событие name.

    @param {string} name
    @param {no.events.type_handler} handler
*/
no.events.on = function(name, handler) {
    var handlers = no.events._get(name);

    var hid = handler[ no.events._expando ];
    if (!hid) {
        handler[ no.events._expando ] = no.events._hid++;
    } else {
        var i = no.array.firstMatch(handlers, function(handler) { // Ищем этот обработчик среди уже подписанных.
            return ( handler[ no.events._expando ] === hid );
        });
        if (i !== -1) { return; } // Этот обработчик уже подписан.
    }

    handlers.push(handler);
};

/**
    Отписываем обработчик handler от события name.
    Если не передать handler, то удалятся вообще все обработчики события name.

    @param {string} name
    @param {no.events.type_handler=} handler
*/
no.events.off = function(name, handler) {
    if (handler) {
        var hid = handler[ no.events._expando ];

        var handlers = no.events._get(name);
        var i = no.array.firstMatch(handlers, function(handler) { // Ищем этот хэндлер среди уже забинженных обработчиков этого события.
            return ( handler._hid === hid );
        });

        if (i !== -1) {
            handlers.splice(i, 1); // Нашли и удаляем этот обработчик.
        }
    } else {
        delete no.events._handlers[name]; // Удаляем всех обработчиков этого события.
    }
};

// ------------------------------------------------------------------------------------------------------------- //

/**
    "Генерим" событие name. Т.е. вызываем по-очереди (в порядке подписки) все обработчики события name.
    В каждый передаем name и params.

    @param {string} name
    @param {*=} params
*/
no.events.trigger = function(name, params) {
    var handlers = no.events._get(name).slice(); // Копируем список хэндлеров. Если вдруг внутри какого-то обработчика будет вызван off(),
                                                 // то мы не потеряем вызов следующего обработчика.
    for (var i = 0, l = handlers.length; i < l; i++) {
        handlers[i](name, params);
    }
};
<commit_msg>Переделан интерфейс no.events. Теперь no.Events это миксин, который можно подмешивать к любому объекту<commit_after>// ------------------------------------------------------------------------------------------------------------- //
// no.events
// ------------------------------------------------------------------------------------------------------------- //

/**
    Простейший pub/sub.

    no.Events --- объект, который можно подмиксовать к любому другому объекту:

        var foo = {};
        no.extend( foo, no.Events );

        foo.on('bar', function(e, data) {
            console.log(e, data);
        });

        foo.trigger('bar', 42);

    Или же:

        function Foo() {}

        no.extend( Foo.prototype, no.Events );

        var foo = new Foo();

        foo.on('bar', function(e, data) {
            console.log(e, data);
        });

        foo.trigger('bar', 42);

    Для общение с "космосом" есть специальный предопределенный объект no.events.
    Через него нужно обмениваться сообщениями, не привязанными к какому-то конкретному инстансу объекта.

        no.events.on('bar', function(e, data) {
            console.log(e, data);
        });

        no.events.trigger('bar', 42);

*/

no.Events = {};

// ------------------------------------------------------------------------------------------------------------- //

/**
    Тип для обработчиков событий.
    @typedef {function(string, *=)}
*/
no.Events.type_handler;

// ------------------------------------------------------------------------------------------------------------- //

/**
    Возвращает список обработчиков события name.
    Если еще ни одного обработчика не забинжено, возвращает (и сохраняет) пустой список.

    @param {string} name
    @return {Array.<no.Events.type_handler>}
*/
no.Events._getEventHandlers = function(name) {
    var handlers = this._eventHandlers || (( this._eventHandlers = {} ));

    return handlers[name] || (( handlers[name] = [] ));
};

// ------------------------------------------------------------------------------------------------------------- //

/**
    Подписываем обработчик handler на событие name.

    @param {string} name
    @param {no.Events.type_handler} handler
*/
no.Events.on = function(name, handler) {
    var handlers = this._getEventHandlers(name);

    handlers.push(handler);
};

/**
    Отписываем обработчик handler от события name.
    Если не передать handler, то удалятся вообще все обработчики события name.

    @param {string} name
    @param {no.Events.type_handler=} handler
*/
no.Events.off = function(name, handler) {
    if (handler) {
        var handlers = this._getEventHandlers(name);
        var i = no.array.indexOf(handlers, handler); // Ищем этот хэндлер среди уже забинженных обработчиков этого события.

        if (i !== -1) {
            handlers.splice(i, 1); // Нашли и удаляем этот обработчик.
        }
    } else {
        var handlers = this._eventHandlers;
        if (handlers) {
            delete handlers[name]; // Удаляем всех обработчиков этого события.
        }
    }
};

// ------------------------------------------------------------------------------------------------------------- //

/**
    "Генерим" событие name. Т.е. вызываем по-очереди (в порядке подписки) все обработчики события name.
    В каждый передаем name и params.

    @param {string} name
    @param {*=} params
*/
no.Events.trigger = function(name, params) {
    var handlers = this._getEventHandlers(name).slice(); // Копируем список хэндлеров. Если вдруг внутри какого-то обработчика будет вызван off(),
                                                         // то мы не потеряем вызов следующего обработчика.
    for (var i = 0, l = handlers.length; i < l; i++) {
        handlers[i](name, params);
    }
};

// ------------------------------------------------------------------------------------------------------------- //

// Создаем "космос" --- дефолтный канал для обмена сообщениями.

no.events = no.extend( {}, no.Events );

{'fraction_non_alphanumeric': 0.3102996989922785, 'fraction_numerical': 0.0018322209134929983, 'mean_word_length': 1.2737280571258554, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3263930', 'n_tokens_mistral': 2264, 'n_tokens_neox': 2345, 'n_words': 518}