<commit_before><script type="text/javascript"><!--
'use strict';
$(() => {

  const review = cd.review;

  review.refreshFiles = (params) => {
    const args = { id:params.id, was_index:params.wasIndex, now_index:params.nowIndex };
    review.getJSON('differ', 'diff_lines', args, (diff_lines) => {
      refreshFilesResponder(diff_lines);
    });
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const refreshFilesResponder = (diffs) => {
    augmentDiffs(diffs);
    const $diffContent = $('#diff-content');
    $diffContent.html(makeDiffContent(diffs));

    const $diffFilenames = $('#diff-filenames');
    $diffFilenames.html($makeDiffFilenames(diffs));
    resetFilenameAddedDeletedLineCountHandlers();

    const picked = review.pick_file(diffs, review.filename);
    review.selectFilename(picked);
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const augmentDiffs = (diffs) => {
    diffs.forEach((diff,index) => {
      diff.id = `id_${index}`;
      diff.chunkIndex = 0
      diff.chunkCount = chunkCount(diff.lines);
      diff.hasBeenClicked = false;
      diff.filename = (diff.type === 'deleted') ? diff.old_filename : diff.new_filename;
    });
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const chunkCount = (lines) => lines.reduce((n,line) => n + (line.type === 'section'), 0);

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const $makeDiffFilenames = (diffs) => {
    const $table = $('<table>', { class:'filenames' });
    $table.append($makeIconHeadings());
    sortedDiffs(diffs).forEach(diff => $table.append($makeDiffTr(diff)));
    return $table;
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const $makeIconHeadings = () => {
    const $tr = $('<tr>');
    if (review.inDiffMode()) {
      $tr.append(
        $makeTd($makeDiffLineCountIcon('deleted', '&mdash;')),
        $makeTd($makeDiffLineCountIcon('added', '+')),
        $makeTd($makeDiffLineCountIcon('same', '=')),
        $makeTd($makeDiffHelpIcon()) // Aligns withs glyph-id
      )
    }
    $tr.append($makeTd('')); // Aligns with filename-td
    return $tr;
  };

  const $makeTd = ($node) => $('<td>').html($node);

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const $makeDiffTr = (diff) => {
    const $tr = $('<tr>');
    if (review.inDiffMode()) {
      $tr.append(
        $makeTd($makeDiffCount(diff, 'deleted')),
        $makeTd($makeDiffCount(diff, 'added')),
        $makeTd($makeDiffCount(diff, 'same')),
        $makeTd($makeDiffType(diff))
      );
    }
    $tr.append($makeTd(review.makeDiffFilename(diff)));
    return $tr;
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const $makeDiffLineCountIcon = (cssName, icon) => {
    return $('<div>', {
      class:`diff-line-count-icon ${cssName}`
    }).html(icon);
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const $makeDiffHelpIcon = () => {
    let tip = '';
    tip += '<span class="diff-line-count-icon deleted">-</span> ';
    tip += '<span class="diff-line-count-icon added">+</span> ';
    tip += '<span class="diff-line-count-icon same">=</span> number of deleted,added,unchanged lines.<br/>';
    tip += '<hr/>';
    tip += 'click a filename to review it.<br/>';
    tip += 'reclick the filename to cycle through its diff-chunks.<br/>';
    tip += '<hr/>';
    tip += '<table>';
    tip += tr3('changed', 'hover over <span class="diff-type-marker changed"></span> for diff-chunk count');
    tip += tr3('renamed', 'hover over <span class="diff-type-marker renamed"></span> for old filename');
    tip += tr3('created', '');
    tip += tr3('deleted', '');
    tip += tr3('unchanged', '');
    tip += '</table>';
    const $div = $('<div>', {
      class: 'diff-help-icon',
      'data-tip': tip
    });
    $div.text('?');
    cd.setupHoverTips($div);
    return $div;
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const tr3 = (type, info) => {
    return `<tr><td><span class="diff-type-marker ${type}"></span></td>` +
               `<td><span class="diff-filename ${type}">${type}-file</span></td>` +
               `<td>${info}</td>`;
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const $makeDiffCount = (diff, cssName) => {
    const lineCount = diff.line_counts[cssName];
    const css = lineCount > 0 ? cssName : '';
    const $div = $('<div>', {
      class: `diff-line-count ${css}`,
      'data-diff-id': diff.id
    });
    $div.html(lineCount > 0 ? lineCount : '&nbsp;');
    return $div;
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const $makeDiffType = (diff) => {
    if (diff === '&nbsp;') { return diff; }
    const $div = $('<div>', { class:`diff-type-marker ${diff.type}` });
    let hoverTip = '';
    if (diff.type === 'renamed') {
      hoverTip += oldFilenameTip(diff);
    }
    if (diff.chunkCount > 0) {
      if (hoverTip != '') { hoverTip += '<br/>'; }
      hoverTip += chunkCountTip(diff);
    }
    if (hoverTip != '') {
      $div.attr('data-tip', hoverTip);
      cd.setupHoverTips($div);
    }
    return $div;
  };

  const oldFilenameTip = (diff) => {
    const filename = cd.htmlEscape(diff.old_filename);
    return `was<span class="diff-filename renamed">${filename}</span>`;
  };

  const chunkCountTip = (diff) => {
    return `diff chunk count == ${diff.chunkCount}`;
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  review.makeDiffFilename = (diff) => {
    return $('<div>', {
      class: `diff-filename ${diff.type}`,
         id: `diff-filename-${diff.id}`,
      'data-diff-id': diff.id
    }).text(cd.htmlEscape(diff.filename))
      .click(() => review.selectFilename(diff));
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const sortedDiffs = (diffs) => {
    // Ensure filenames appear in the same order as kata/edit page
    const filenames = diffs.map(diff => diff.filename);
    const sorted = cd.sortedFilenames(filenames);
    const diffFor = (filename) => diffs.find(diff => diff.filename === filename);
    return sorted.map(filename => diffFor(filename));
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const resetFilenameAddedDeletedLineCountHandlers = () => {

    const display = (node, type, value) => {
      const $node = $(node);
      // Only [+][-] counts for current filename are live
      if ($node.html() === '&nbsp;') { return; }
      if ($node.attr('disabled') !== 'disabled') {
        const id = $node.data('diff-id');
        const selector = `#file-content-${id} ${type}`;
        $(selector).css('display', value);
        if (value === 'none') {
          $node.removeClass('on').addClass('off');
        } else {
          $node.removeClass('off').addClass('on');
        }
      }
    };

    [ 'deleted', 'added' ].forEach(type => { // not 'same'
      $(`.diff-line-count.${type}`)
        .clickToggle(
          function() { display(this, type, 'none' ); },
          function() { display(this, type, 'block'); }
        );
    });
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  review.selectFilename = (diff) => {
    // show filename
    $('.diff-filename', review.page).removeClass('selected');
    $(`#diff-filename-${diff.id}`, review.page).addClass('selected');
    // show diff line-counts
    $('.diff-line-count').attr('disabled', true);
    $(`.diff-line-count[data-diff-id="${diff.id}"]`).attr('disabled', false);
    // show file content
    $('.file-content', review.page).hide();
    $(`#file-content-${diff.id}`, review.page).show();

    scrollToNextDiffChunkOnReclick(diff, diff.filename);
    review.filename = diff.filename;
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const scrollToNextDiffChunkOnReclick = (diff, filename) => {
    const hasDiffChunks = () => diff.chunkCount > 0;
    const isFirstClick = () => !diff.hasBeenClicked;
    const isReClick = () => review.filename === filename;
    if (hasDiffChunks() && (isFirstClick() || isReClick())) {
      const $diffSheet = $(`#diff-sheet-${diff.id}`);
      const $diffChunk = $(`#diff-chunk-${diff.id}-${diff.chunkIndex}`);
      const position = { scrollTop: '+=' + ($diffChunk.offset().top - 250) + 'px' };
      const halfSecond = 500;
      $diffSheet.animate(position, halfSecond);
      diff.chunkIndex += 1;
      diff.chunkIndex %= diff.chunkCount;
    }
    diff.hasBeenClicked = true;
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const makeDiffContent = (diffs) => {
    const $holder = $('<span>');
    diffs.forEach(diff => {
      $holder.append(review.makeDiffFileContent(diff));
    });
    return $holder;
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  review.makeDiffFileContent = (diff) => {
    const lineNumbers = makeLineNumbers(diff.lines);
    const fileContent = makeContent(diff.id, diff.lines);
    const $file = $('' +
      `<div id="file-content-${diff.id}" class="file-content">` +
      '<table>' +
        '<tr class="valign-top">' +
          makeTd('<div class="diff-line-numbers"></div>') +
          makeTd(`<div id="diff-sheet-${diff.id}"` +
                 ' class="diff-sheet"></div>') +
        '</tr>' +
      '</table>' +
      '</div>'
      );
    const $numbers = $('.diff-line-numbers', $file);
    $numbers.html(lineNumbers);

    const $content = $('.diff-sheet', $file);
    $content.html(fileContent);

    bindLineNumberScrolling($content, $numbers);
    return $file;
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const makeLineNumbers = (lines) => {
    let html = [];
    lines.forEach(line => {
      if (line.type != 'section') {
        html.push(`<${line.type}><ln>${line.number}</ln></${line.type}>`);
      }
    });
    return html;
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const makeContent = (id, diff_lines) => {
    let html = [];
    diff_lines.forEach(diff_line => {
      if (diff_line.type === 'section') {
        html.push(`<span id='diff-chunk-${id}-${diff_line.index}'></span>`);
      } else {
        let line = cd.htmlEscape(diff_line.line);
        if (line === '') { line = '&nbsp'; }
        html.push(`<${diff_line.type}>${line}</${diff_line.type}>`);
      }
    });
    return html;
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const bindLineNumberScrolling = ($content, $numbers) => {
    const synchScroll = () => $numbers.scrollTop($content.scrollTop());
    $content.bind({
      keydown   : synchScroll,
      scroll    : synchScroll,
      mousewheel: synchScroll,
      mousemove : synchScroll,
      mousedown : synchScroll,
      mouseup   : synchScroll
    });
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const makeTd = (html) => `<td>${html}</td>`;

});
//--></script>

<div id="diff-filenames"></div>
<commit_msg>Refactoring; collapse review JS duplication.<commit_after><script type="text/javascript"><!--
'use strict';
$(() => {

  const review = cd.review;

  review.refreshFiles = (params) => {
    const args = { id:params.id, was_index:params.wasIndex, now_index:params.nowIndex };
    review.getJSON('differ', 'diff_lines', args, (diff_lines) => {
      refreshFilesResponder(diff_lines);
    });
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const refreshFilesResponder = (diffs) => {
    augmentDiffs(diffs);
    const $diffContent = $('#diff-content');
    $diffContent.html(makeDiffContent(diffs));

    const $diffFilenames = $('#diff-filenames');
    $diffFilenames.html($makeDiffFilenames(diffs));
    resetFilenameAddedDeletedLineCountHandlers();

    const picked = review.pick_file(diffs, review.filename);
    review.selectFilename(picked);
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const augmentDiffs = (diffs) => {
    diffs.forEach((diff,index) => {
      diff.id = `id_${index}`;
      diff.chunkIndex = 0
      diff.chunkCount = chunkCount(diff.lines);
      diff.hasBeenClicked = false;
      diff.filename = (diff.type === 'deleted') ? diff.old_filename : diff.new_filename;
    });
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const chunkCount = (lines) => lines.reduce((n,line) => n + (line.type === 'section'), 0);

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const $makeDiffFilenames = (diffs) => {
    const $table = $('<table>', { class:'filenames' });
    $table.append($makeIconHeadings());
    sortedDiffs(diffs).forEach(diff => $table.append($makeDiffTr(diff)));
    return $table;
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const $makeIconHeadings = () => {
    const $tr = $('<tr>');
    if (review.inDiffMode()) {
      $tr.append(
        $makeDiffLineCountIconTd('deleted', '&mdash;'),
        $makeDiffLineCountIconTd('added', '+'),
        $makeDiffLineCountIconTd('same', '='),
        $makeDiffHelpIconTd() // Aligns withs glyph-id
      )
    }
    $tr.append($makeTd('')); // Aligns with filename-td
    return $tr;
  };

  const $makeTd = ($node) => $('<td>').html($node);

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const $makeDiffTr = (diff) => {
    const $tr = $('<tr>');
    if (review.inDiffMode()) {
      $tr.append(
        $makeDiffCountTd(diff, 'deleted'),
        $makeDiffCountTd(diff, 'added'),
        $makeDiffCountTd(diff, 'same'),
        $makeDiffTypeTd(diff)
      );
    }
    $tr.append($makeTd(review.makeDiffFilename(diff)));
    return $tr;
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const $makeDiffLineCountIconTd = (cssName, icon) => {
    const $icon = $('<div>', {
      class:`diff-line-count-icon ${cssName}`
    }).html(icon);
    return $('<td>').append($icon);
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const $makeDiffHelpIconTd = () => {
    let tip = '';
    tip += '<span class="diff-line-count-icon deleted">-</span> ';
    tip += '<span class="diff-line-count-icon added">+</span> ';
    tip += '<span class="diff-line-count-icon same">=</span> number of deleted,added,unchanged lines.<br/>';
    tip += '<hr/>';
    tip += 'click a filename to review it.<br/>';
    tip += 'reclick the filename to cycle through its diff-chunks.<br/>';
    tip += '<hr/>';
    tip += '<table>';
    tip += tr3('changed', 'hover over <span class="diff-type-marker changed"></span> for diff-chunk count');
    tip += tr3('renamed', 'hover over <span class="diff-type-marker renamed"></span> for old filename');
    tip += tr3('created', '');
    tip += tr3('deleted', '');
    tip += tr3('unchanged', '');
    tip += '</table>';
    const $div = $('<div>', {
      class: 'diff-help-icon',
      'data-tip': tip
    });
    $div.text('?');
    cd.setupHoverTips($div);
    return $('<td>').append($div);
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const tr3 = (type, info) => {
    return `<tr><td><span class="diff-type-marker ${type}"></span></td>` +
               `<td><span class="diff-filename ${type}">${type}-file</span></td>` +
               `<td>${info}</td>`;
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const $makeDiffCountTd = (diff, cssName) => {
    const lineCount = diff.line_counts[cssName];
    const css = lineCount > 0 ? cssName : '';
    const $div = $('<div>', {
      class: `diff-line-count ${css}`,
      'data-diff-id': diff.id
    });
    $div.html(lineCount > 0 ? lineCount : '&nbsp;');
    return $('<td>').append($div);
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const $makeDiffTypeTd = (diff) => {
    if (diff === '&nbsp;') { return diff; }
    const $div = $('<div>', { class:`diff-type-marker ${diff.type}` });
    let hoverTip = '';
    if (diff.type === 'renamed') {
      hoverTip += oldFilenameTip(diff);
    }
    if (diff.chunkCount > 0) {
      if (hoverTip != '') { hoverTip += '<br/>'; }
      hoverTip += chunkCountTip(diff);
    }
    if (hoverTip != '') {
      $div.attr('data-tip', hoverTip);
      cd.setupHoverTips($div);
    }
    return $('<td>').append($div);
  };

  const oldFilenameTip = (diff) => {
    const filename = cd.htmlEscape(diff.old_filename);
    return `was<span class="diff-filename renamed">${filename}</span>`;
  };

  const chunkCountTip = (diff) => {
    return `diff chunk count == ${diff.chunkCount}`;
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  review.makeDiffFilename = (diff) => {
    return $('<div>', {
      class: `diff-filename ${diff.type}`,
         id: `diff-filename-${diff.id}`,
      'data-diff-id': diff.id
    }).text(cd.htmlEscape(diff.filename))
      .click(() => review.selectFilename(diff));
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const sortedDiffs = (diffs) => {
    // Ensure filenames appear in the same order as kata/edit page
    const filenames = diffs.map(diff => diff.filename);
    const sorted = cd.sortedFilenames(filenames);
    const diffFor = (filename) => diffs.find(diff => diff.filename === filename);
    return sorted.map(filename => diffFor(filename));
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const resetFilenameAddedDeletedLineCountHandlers = () => {

    const display = (node, type, value) => {
      const $node = $(node);
      // Only [+][-] counts for current filename are live
      if ($node.html() === '&nbsp;') { return; }
      if ($node.attr('disabled') !== 'disabled') {
        const id = $node.data('diff-id');
        const selector = `#file-content-${id} ${type}`;
        $(selector).css('display', value);
        if (value === 'none') {
          $node.removeClass('on').addClass('off');
        } else {
          $node.removeClass('off').addClass('on');
        }
      }
    };

    [ 'deleted', 'added' ].forEach(type => { // not 'same'
      $(`.diff-line-count.${type}`)
        .clickToggle(
          function() { display(this, type, 'none' ); },
          function() { display(this, type, 'block'); }
        );
    });
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  review.selectFilename = (diff) => {
    // show filename
    $('.diff-filename', review.page).removeClass('selected');
    $(`#diff-filename-${diff.id}`, review.page).addClass('selected');
    // show diff line-counts
    $('.diff-line-count').attr('disabled', true);
    $(`.diff-line-count[data-diff-id="${diff.id}"]`).attr('disabled', false);
    // show file content
    $('.file-content', review.page).hide();
    $(`#file-content-${diff.id}`, review.page).show();

    scrollToNextDiffChunkOnReclick(diff, diff.filename);
    review.filename = diff.filename;
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const scrollToNextDiffChunkOnReclick = (diff, filename) => {
    const hasDiffChunks = () => diff.chunkCount > 0;
    const isFirstClick = () => !diff.hasBeenClicked;
    const isReClick = () => review.filename === filename;
    if (hasDiffChunks() && (isFirstClick() || isReClick())) {
      const $diffSheet = $(`#diff-sheet-${diff.id}`);
      const $diffChunk = $(`#diff-chunk-${diff.id}-${diff.chunkIndex}`);
      const position = { scrollTop: '+=' + ($diffChunk.offset().top - 250) + 'px' };
      const halfSecond = 500;
      $diffSheet.animate(position, halfSecond);
      diff.chunkIndex += 1;
      diff.chunkIndex %= diff.chunkCount;
    }
    diff.hasBeenClicked = true;
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const makeDiffContent = (diffs) => {
    const $holder = $('<span>');
    diffs.forEach(diff => {
      $holder.append(review.makeDiffFileContent(diff));
    });
    return $holder;
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  review.makeDiffFileContent = (diff) => {
    const lineNumbers = makeLineNumbers(diff.lines);
    const fileContent = makeContent(diff.id, diff.lines);
    const $file = $('' +
      `<div id="file-content-${diff.id}" class="file-content">` +
      '<table>' +
        '<tr class="valign-top">' +
          makeTd('<div class="diff-line-numbers"></div>') +
          makeTd(`<div id="diff-sheet-${diff.id}"` +
                 ' class="diff-sheet"></div>') +
        '</tr>' +
      '</table>' +
      '</div>'
      );
    const $numbers = $('.diff-line-numbers', $file);
    $numbers.html(lineNumbers);

    const $content = $('.diff-sheet', $file);
    $content.html(fileContent);

    bindLineNumberScrolling($content, $numbers);
    return $file;
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const makeLineNumbers = (lines) => {
    let html = [];
    lines.forEach(line => {
      if (line.type != 'section') {
        html.push(`<${line.type}><ln>${line.number}</ln></${line.type}>`);
      }
    });
    return html;
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const makeContent = (id, diff_lines) => {
    let html = [];
    diff_lines.forEach(diff_line => {
      if (diff_line.type === 'section') {
        html.push(`<span id='diff-chunk-${id}-${diff_line.index}'></span>`);
      } else {
        let line = cd.htmlEscape(diff_line.line);
        if (line === '') { line = '&nbsp'; }
        html.push(`<${diff_line.type}>${line}</${diff_line.type}>`);
      }
    });
    return html;
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const bindLineNumberScrolling = ($content, $numbers) => {
    const synchScroll = () => $numbers.scrollTop($content.scrollTop());
    $content.bind({
      keydown   : synchScroll,
      scroll    : synchScroll,
      mousewheel: synchScroll,
      mousemove : synchScroll,
      mousedown : synchScroll,
      mouseup   : synchScroll
    });
  };

  // - - - - - - - - - - - - - - - - - - - - - - - -
  const makeTd = (html) => `<td>${html}</td>`;

});
//--></script>

<div id="diff-filenames"></div>

{'fraction_non_alphanumeric': 0.23844372394627142, 'fraction_numerical': 0.0017600741083835109, 'mean_word_length': 1.9846557920928947, 'pattern_counts': {'":': 0, '<': 139, '<?xml version=': 0, '>': 237, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 132, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '653447', 'n_tokens_mistral': 7670, 'n_tokens_neox': 7588, 'n_words': 1161}