<commit_before>ko.forcibleComputed = function(readFunc, context, options) {
    var trigger = ko.observable(),
        target = ko.computed(function() {
            trigger();
            return readFunc.call(context);
        }, null, options);
    target.evaluateImmediate = function() {
        trigger.valueHasMutated();
    };
    return target;
};

function timeOutput(startedAt, finishedAt, lastChangeAt, isRunning) {
    if (!isRunning) { 
        return 'finished ' + moment(finishedAt).calendar() + ' [finished ' + moment(finishedAt).fromNow() + '] (ran for ' + countdown(startedAt, finishedAt).toString() + ')';
    } else {
        return 'running for ' + countdown(startedAt).toString() + ' [started ' + moment(startedAt).fromNow() + ']';
    }
}

var BuildViewModel = function (build) {
    this.isRunning = ko.observable(build.isRunning);
    this.project = ko.observable(build.project);
    this.definition = ko.observable(build.definition);
    this.number = ko.observable(build.number);
    this.startedAt = ko.observable(moment(build.startedAt));
    this.finishedAt = ko.observable(moment(build.finishedAt));
    this.lastChangeAt = ko.observable(moment(build.lastChangeAt));
    this.status = ko.observable(build.status);
    this.reason = ko.observable(build.reason);
    this.requestedFor = ko.observable(build.requestedFor);
    this.hasWarnings = ko.observable(build.hasWarnings);
    this.hasErrors = ko.observable(build.hasErrors);

    this.cssClass = ko.computed(function () {
        return this.status() + '-color';
    }, this);

    this.duration = ko.forcibleComputed(function () {
        return timeOutput(this.startedAt(), this.finishedAt(), this.lastChangeAt(), this.isRunning());
    }, this);

    setInterval(function (buildViewModel) {
        buildViewModel.duration.evaluateImmediate();
    }, 1000, this);
};

var AppViewModel = function() {
    this.builds = ko.observableArray([]);
};

var app = new AppViewModel();

$(function() {
    app.builds.push(new BuildViewModel({ project: 'Loading...'}));<commit_msg>Improvment of client side timer.<commit_after>ko.forcibleComputed = function(readFunc, context, options) {
    var trigger = ko.observable(),
        target = ko.computed(function() {
            trigger();
            return readFunc.call(context);
        }, null, options);
    target.evaluateImmediate = function() {
        trigger.valueHasMutated();
    };
    return target;
};

function timeOutput(startedAt, finishedAt, lastChangeAt, isRunning) {
    if (!isRunning) { 
        return 'finished ' + moment(finishedAt).calendar() + ' [finished ' + moment(finishedAt).fromNow() + '] (ran for ' + countdown(startedAt, finishedAt).toString() + ')';
    } else {
        return 'running for ' + countdown(startedAt).toString() + ' [started ' + moment(startedAt).fromNow() + ']';
    }
}

var BuildViewModel = function (build) {
    this.isRunning = ko.observable(build.isRunning);
    this.project = ko.observable(build.project);
    this.definition = ko.observable(build.definition);
    this.number = ko.observable(build.number);
    this.startedAt = ko.observable(moment(build.startedAt));
    this.finishedAt = ko.observable(moment(build.finishedAt));
    this.lastChangeAt = ko.observable(moment(build.lastChangeAt));
    this.status = ko.observable(build.status);
    this.reason = ko.observable(build.reason);
    this.requestedFor = ko.observable(build.requestedFor);
    this.hasWarnings = ko.observable(build.hasWarnings);
    this.hasErrors = ko.observable(build.hasErrors);

    this.cssClass = ko.computed(function () {
        return this.status() + '-color';
    }, this);

    this.duration = ko.forcibleComputed(function () {
        return timeOutput(this.startedAt(), this.finishedAt(), this.lastChangeAt(), this.isRunning());
    }, this);
};

var AppViewModel = function() {
    this.builds = ko.observableArray([]);
};

var app = new AppViewModel();

$(function() {
    setInterval(function () {
        app.builds().forEach(function (build) {
            build.duration.evaluateImmediate();
        })
    }, 1000);

    app.builds.push(new BuildViewModel({ project: 'Loading...'}));
{'fraction_non_alphanumeric': 0.15358771298296137, 'fraction_numerical': 0.001919846412287017, 'mean_word_length': 3.565169769989047, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '3687776', 'n_tokens_mistral': 1278, 'n_tokens_neox': 1231, 'n_words': 209}