<commit_before>import Ansi from 'ansi-to-html';
import Entities from 'html-entities';

const ELEMENT_TBODY = '#atStdoutResultTable';
const EVENT_START_TASK = 'playbook_on_task_start';
const EVENT_START_PLAY = 'playbook_on_play_start';
const EVENT_STATS_PLAY = 'playbook_on_stats';

const EVENT_GROUPS = [
    EVENT_START_TASK,
    EVENT_START_PLAY
];

const TIME_EVENTS = [
    EVENT_START_TASK,
    EVENT_START_PLAY,
    EVENT_STATS_PLAY
];

const ansi = new Ansi();
const entities = new Entities.AllHtmlEntities();

// https://github.com/chalk/ansi-regex
const pattern = [
    '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\\u0007)',
    '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))'
].join('|');

const re = new RegExp(pattern);
const hasAnsi = input => re.test(input);

function JobRenderService ($q, $sce, $window) {
    this.init = ({ compile, apply, isStreamActive }) => {
        this.parent = null;
        this.record = {};
        this.el = $(ELEMENT_TBODY);
        this.hooks = { isStreamActive, compile, apply };
    };

    this.sortByLineNumber = (a, b) => {
        if (a.start_line > b.start_line) {
            return 1;
        }

        if (a.start_line < b.start_line) {
            return -1;
        }

        return 0;
    };

    this.transformEventGroup = events => {
        let lines = 0;
        let html = '';

        events.sort(this.sortByLineNumber);

        events.forEach(event => {
            const line = this.transformEvent(event);

            html += line.html;
            lines += line.count;
        });

        return { html, lines };
    };

    this.transformEvent = event => {
        if (!event || !event.stdout) {
            return { html: '', count: 0 };
        }

        const stdout = this.sanitize(event.stdout);
        const lines = stdout.split('\r\n');

        let count = lines.length;
        let ln = event.start_line;

        const current = this.createRecord(ln, lines, event);

        const html = lines.reduce((concat, line, i) => {
            ln++;

            const isLastLine = i === lines.length - 1;

            let row = this.createRow(current, ln, line);

            if (current && current.isTruncated && isLastLine) {
                row += this.createRow(current);
                count++;
            }

            return `${concat}${row}`;
        }, '');

        return { html, count };
    };

    this.createRecord = (ln, lines, event) => {
        if (!event.uuid) {
            return null;
        }

        const info = {
            id: event.id,
            line: ln + 1,
            uuid: event.uuid,
            level: event.event_level,
            start: event.start_line,
            end: event.end_line,
            isTruncated: (event.end_line - event.start_line) > lines.length,
            isHost: typeof event.host === 'number'
        };

        if (event.parent_uuid) {
            info.parents = this.getParentEvents(event.parent_uuid);
        }

        if (info.isTruncated) {
            info.truncatedAt = event.start_line + lines.length;
        }

        if (EVENT_GROUPS.includes(event.event)) {
            info.isParent = true;

            if (event.event_level === 1) {
                this.parent = event.uuid;
            }

            if (event.parent_uuid) {
                if (this.record[event.parent_uuid]) {
                    if (this.record[event.parent_uuid].children &&
                        !this.record[event.parent_uuid].children.includes(event.uuid)) {
                        this.record[event.parent_uuid].children.push(event.uuid);
                    } else {
                        this.record[event.parent_uuid].children = [event.uuid];
                    }
                }
            }
        }

        if (TIME_EVENTS.includes(event.event)) {
            info.time = this.getTimestamp(event.created);
            info.line++;
        }

        this.record[event.uuid] = info;

        return info;
    };

    this.createRow = (current, ln, content) => {
        let id = '';
        let timestamp = '';
        let tdToggle = '';
        let tdEvent = '';
        let classList = '';

        content = content || '';

        if (hasAnsi(content)) {
            content = ansi.toHtml(content);
        }

        if (current) {
            if (!this.hooks.isStreamActive() && current.isParent && current.line === ln) {
                id = current.uuid;
                tdToggle = `<td class="at-Stdout-toggle" ng-click="vm.toggle('${id}')"><i class="fa fa-angle-down can-toggle"></i></td>`;
            }

            if (current.isHost) {
                tdEvent = `<td class="at-Stdout-event--host" ui-sref="jobz.host-event.json({eventId: ${current.id},  taskUuid: '${current.uuid}' })">${content}</td>`;
            }

            if (current.time && current.line === ln) {
                timestamp = `<span>${current.time}</span>`;
            }

            if (current.parents) {
                classList = current.parents.reduce((list, uuid) => `${list} child-of-${uuid}`, '');
            }
        }

        if (!tdEvent) {
            tdEvent = `<td class="at-Stdout-event">${content}</td>`;
        }<commit_msg>Adds NgNonBindable directive to stdout lines<commit_after>import Ansi from 'ansi-to-html';
import Entities from 'html-entities';

const ELEMENT_TBODY = '#atStdoutResultTable';
const EVENT_START_TASK = 'playbook_on_task_start';
const EVENT_START_PLAY = 'playbook_on_play_start';
const EVENT_STATS_PLAY = 'playbook_on_stats';

const EVENT_GROUPS = [
    EVENT_START_TASK,
    EVENT_START_PLAY
];

const TIME_EVENTS = [
    EVENT_START_TASK,
    EVENT_START_PLAY,
    EVENT_STATS_PLAY
];

const ansi = new Ansi();
const entities = new Entities.AllHtmlEntities();

// https://github.com/chalk/ansi-regex
const pattern = [
    '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\\u0007)',
    '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))'
].join('|');

const re = new RegExp(pattern);
const hasAnsi = input => re.test(input);

function JobRenderService ($q, $sce, $window) {
    this.init = ({ compile, apply, isStreamActive }) => {
        this.parent = null;
        this.record = {};
        this.el = $(ELEMENT_TBODY);
        this.hooks = { isStreamActive, compile, apply };
    };

    this.sortByLineNumber = (a, b) => {
        if (a.start_line > b.start_line) {
            return 1;
        }

        if (a.start_line < b.start_line) {
            return -1;
        }

        return 0;
    };

    this.transformEventGroup = events => {
        let lines = 0;
        let html = '';

        events.sort(this.sortByLineNumber);

        events.forEach(event => {
            const line = this.transformEvent(event);

            html += line.html;
            lines += line.count;
        });

        return { html, lines };
    };

    this.transformEvent = event => {
        if (!event || !event.stdout) {
            return { html: '', count: 0 };
        }

        const stdout = this.sanitize(event.stdout);
        const lines = stdout.split('\r\n');

        let count = lines.length;
        let ln = event.start_line;

        const current = this.createRecord(ln, lines, event);

        const html = lines.reduce((concat, line, i) => {
            ln++;

            const isLastLine = i === lines.length - 1;

            let row = this.createRow(current, ln, line);

            if (current && current.isTruncated && isLastLine) {
                row += this.createRow(current);
                count++;
            }

            return `${concat}${row}`;
        }, '');

        return { html, count };
    };

    this.createRecord = (ln, lines, event) => {
        if (!event.uuid) {
            return null;
        }

        const info = {
            id: event.id,
            line: ln + 1,
            uuid: event.uuid,
            level: event.event_level,
            start: event.start_line,
            end: event.end_line,
            isTruncated: (event.end_line - event.start_line) > lines.length,
            isHost: typeof event.host === 'number'
        };

        if (event.parent_uuid) {
            info.parents = this.getParentEvents(event.parent_uuid);
        }

        if (info.isTruncated) {
            info.truncatedAt = event.start_line + lines.length;
        }

        if (EVENT_GROUPS.includes(event.event)) {
            info.isParent = true;

            if (event.event_level === 1) {
                this.parent = event.uuid;
            }

            if (event.parent_uuid) {
                if (this.record[event.parent_uuid]) {
                    if (this.record[event.parent_uuid].children &&
                        !this.record[event.parent_uuid].children.includes(event.uuid)) {
                        this.record[event.parent_uuid].children.push(event.uuid);
                    } else {
                        this.record[event.parent_uuid].children = [event.uuid];
                    }
                }
            }
        }

        if (TIME_EVENTS.includes(event.event)) {
            info.time = this.getTimestamp(event.created);
            info.line++;
        }

        this.record[event.uuid] = info;

        return info;
    };

    this.createRow = (current, ln, content) => {
        let id = '';
        let timestamp = '';
        let tdToggle = '';
        let tdEvent = '';
        let classList = '';

        content = content || '';

        if (hasAnsi(content)) {
            content = ansi.toHtml(content);
        }

        if (current) {
            if (!this.hooks.isStreamActive() && current.isParent && current.line === ln) {
                id = current.uuid;
                tdToggle = `<td class="at-Stdout-toggle" ng-click="vm.toggle('${id}')"><i class="fa fa-angle-down can-toggle"></i></td>`;
            }

            if (current.isHost) {
                tdEvent = `<td class="at-Stdout-event--host" ui-sref="jobz.host-event.json({eventId: ${current.id},  taskUuid: '${current.uuid}' })"><span ng-non-bindable>${content}</span></td>`;
            }

            if (current.time && current.line === ln) {
                timestamp = `<span>${current.time}</span>`;
            }

            if (current.parents) {
                classList = current.parents.reduce((list, uuid) => `${list} child-of-${uuid}`, '');
            }
        }

        if (!tdEvent) {
            tdEvent = `<td class="at-Stdout-event">${content}</td>`;
        }
{'fraction_non_alphanumeric': 0.15573926263778032, 'fraction_numerical': 0.004180919802356519, 'mean_word_length': 1.7280974598237429, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 51, 'https://': 2, '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': '3218046', 'n_tokens_mistral': 3342, 'n_tokens_neox': 3201, 'n_words': 586}