<commit_before>"use strict";

function script_to_narrative(script, options) {
  var options = options || {};
  var too_many = options.too_many || 5;
  var fixed_characters = options.fixed_characters || false;
  var num_frequent = options.num_frequent || 5;

  var char_ids = {};
  var next_id = 0;
  var char_to_id = function(name) {
    if (char_ids[name] == null) {
      char_ids[name] = next_id;
      next_id += 1;
    }
    return char_ids[name];
  };

  var locations = get_locations(script);
  var frequent = options.characters || most_frequent_characters(locations, num_frequent);

  var pos = 0;
  var scenes = [];
  locations.forEach(function(loc) {
    get_characters(loc).map(char_to_id);
    var scene = {
      duration: 2,
      start: pos,
      chars: [...new Set(get_characters(loc))].sort()
    };

    if (fixed_characters || scene.chars.length > too_many) {
      scene.chars = scene.chars.filter(function(c) {
        return frequent.has(c);
      });
    }
    scene.chars = [...new Set(scene.chars).keys()].map(char_to_id).sort();
    pos += 1;

    if (scene.chars.length > 0) {
      scenes.push(scene);
    }
  });

  return {
    narrative: scenes,
    chars: char_ids,
  }
}

function get_json(url, cb) {
  var xhr = new XMLHttpRequest()
  xhr.open("GET", 'http://localhost:4567/api/movie/json/' + encodeURIComponent(url + '.json'))
  //xhr.open("GET", url)
  xhr.send()
  xhr.onload = function() { cb(JSON.parse(xhr.responseText)); };
  return xhr;
}

function get_locations(script) {
  return script.reduce(function(locations, scene) {
    return locations.concat(scene);
  });
}

function most_frequent_characters(locations, num_chars) {
  var num_chars = num_chars || 5;
  var occurrences = {};
  locations.forEach(function(loc) {
    loc.parts
      .filter(is_dialog)
      .forEach(function(dialog) {
        var speaker = normalize_name(dialog.character);
        occurrences[speaker] = (occurrences[speaker] || 0) + 1
      });
  });
  var frequent = Object.keys(occurrences)
      .sort(function(a, b) {
        return occurrences[a] - occurrences[b]
      })
      .reverse()
      .splice(0, num_chars);
  return new Set(frequent);
}

function is_dialog(part) {
  return part.dialog != null;
}

function get_characters(loc) {
  return loc.parts
    .filter(function(part) {
      return part.dialog != null && part.character.trim() != ""
    })
    .map(function(part) {
      return normalize_name(part.character)
    });
}

function normalize_name(name) {
  return name.trim().split(/[^ \.\-A-Za-z]/)[0].trim().toUpperCase();
}

function draw_plot_chart(name, safe_name, prefix, tie_breaker, center_sort, collapse) {
  var folder = prefix.name;

  (function(j) {
    var margin = {top: 20, right: 25, bottom: 20, left: 1};
    var width = raw_chart_width - margin.left - margin.right;

    var jscenes = j; //j['scenes'];
    // This calculation is only relevant for equal_scenes = true
    var scene_width = (width-longest_name)/(jscenes.length+1);

    var total_panels = 0;
    var scenes = []
    for (var i = 0; i < jscenes.length; i++) {
      var duration = parseInt(jscenes[i]['duration']);
      var start;
      if (equal_scenes) {
	start = i*scene_width + longest_name;
      } else {
	start = parseInt(jscenes[i]['start']);
      }
      var chars = jscenes[i]['chars'];
      //if (chars.length == 0) continue;
      scenes[scenes.length] = new SceneNode(jscenes[i]['chars'],
					    start, duration,
					    parseInt(jscenes[i]['id']));
      scenes[scenes.length-1].comic_name = safe_name;
      total_panels += duration;
    } // for

    scenes.sort(function(a, b) { return a.start - b.start; });
    total_panels -= scenes[scenes.length-1].duration;
    scenes[scenes.length-1].duration = 0;


    // Make space at the leftmost end of the chart for character names
    //var total_panels = parseInt(j['panels']);
    var panel_width = Math.min((width-longest_name)/total_panels, 15);
    var panel_shift = Math.round(longest_name/panel_width);
    total_panels += panel_shift;
    panel_width = Math.min(width/total_panels, 15);

    (function(x) {
      var i = 0;
      var xchars = Object.keys(x).map(function(c) {
        return {
          name: c,
          id: x[c],
          group: 1 //i++
        }
      });

      // Calculate chart height based on the number of characters
      // TODO: Redo this calculation
      //var raw_chart_height = xchars.length*(link_width + link_gap + group_gap);// - (link_gap + group_gap);
      var raw_chart_height = 360;
      var height = raw_chart_height - margin.top - margin.bottom;

      var svg = d3.select("#chart").append("svg")
	  .attr("width", width + margin.left + margin.right)
	  .attr("height", height + margin.top + margin.bottom)
          .attr("class", "chart")
          .attr("id", safe_name)
	  .append("g")
	  .attr("transform", "translate(" + margin.left + "," + margin.top + ")");


      var chars = [];
      var char_map = []; // maps id to pointer
      for (var i = 0; i < xchars.length; i++) {
	chars[chars.length] = new Character_(xchars[i].name, xchars[i].id, xchars[i].group);
	char_map[xchars[i].id] = chars[chars.length-1];<commit_msg>Enable specifying of groups for the flow graph<commit_after>"use strict";

function script_to_narrative(script, options) {
  var options = options || {};
  var too_many = options.too_many || 5;
  var fixed_characters = options.fixed_characters || false;
  var num_frequent = options.num_frequent || 5;

  var char_ids = {};
  var next_id = 0;
  var char_to_id = function(name) {
    if (char_ids[name] == null) {
      char_ids[name] = next_id;
      next_id += 1;
    }
    return char_ids[name];
  };

  var locations = get_locations(script);
  var frequent = options.characters || most_frequent_characters(locations, num_frequent);

  var pos = 0;
  var scenes = [];
  locations.forEach(function(loc) {
    get_characters(loc).map(char_to_id);
    var scene = {
      duration: 2,
      start: pos,
      chars: [...new Set(get_characters(loc))].sort()
    };

    if (fixed_characters || scene.chars.length > too_many) {
      scene.chars = scene.chars.filter(function(c) {
        return frequent.has(c);
      });
    }
    scene.chars = [...new Set(scene.chars).keys()].map(char_to_id).sort();
    pos += 1;

    if (scene.chars.length > 0) {
      scenes.push(scene);
    }
  });

  return {
    narrative: scenes,
    chars: char_ids,
    groups: options.groups || {}
  }
}

function get_json(url, cb) {
  var xhr = new XMLHttpRequest()
  xhr.open("GET", 'http://localhost:4567/api/movie/json/' + encodeURIComponent(url + '.json'))
  //xhr.open("GET", url)
  xhr.send()
  xhr.onload = function() { cb(JSON.parse(xhr.responseText)); };
  return xhr;
}

function get_locations(script) {
  return script.reduce(function(locations, scene) {
    return locations.concat(scene);
  });
}

function most_frequent_characters(locations, num_chars) {
  var num_chars = num_chars || 5;
  var occurrences = {};
  locations.forEach(function(loc) {
    loc.parts
      .filter(is_dialog)
      .forEach(function(dialog) {
        var speaker = normalize_name(dialog.character);
        occurrences[speaker] = (occurrences[speaker] || 0) + 1
      });
  });
  var frequent = Object.keys(occurrences)
      .sort(function(a, b) {
        return occurrences[a] - occurrences[b]
      })
      .reverse()
      .splice(0, num_chars);
  return new Set(frequent);
}

function is_dialog(part) {
  return part.dialog != null;
}

function get_characters(loc) {
  return loc.parts
    .filter(function(part) {
      return part.dialog != null && part.character.trim() != ""
    })
    .map(function(part) {
      return normalize_name(part.character)
    });
}

function normalize_name(name) {
  return name.trim().split(/[^ \.\-A-Za-z]/)[0].trim().toUpperCase();
}

function draw_plot_chart(name, safe_name, prefix, tie_breaker, center_sort, collapse) {
  var folder = prefix.name;

  (function(j) {
    var margin = {top: 20, right: 25, bottom: 20, left: 1};
    var width = raw_chart_width - margin.left - margin.right;

    var jscenes = j; //j['scenes'];
    // This calculation is only relevant for equal_scenes = true
    var scene_width = (width-longest_name)/(jscenes.length+1);

    var total_panels = 0;
    var scenes = []
    for (var i = 0; i < jscenes.length; i++) {
      var duration = parseInt(jscenes[i]['duration']);
      var start;
      if (equal_scenes) {
	start = i*scene_width + longest_name;
      } else {
	start = parseInt(jscenes[i]['start']);
      }
      var chars = jscenes[i]['chars'];
      //if (chars.length == 0) continue;
      scenes[scenes.length] = new SceneNode(jscenes[i]['chars'],
					    start, duration,
					    parseInt(jscenes[i]['id']));
      scenes[scenes.length-1].comic_name = safe_name;
      total_panels += duration;
    } // for

    scenes.sort(function(a, b) { return a.start - b.start; });
    total_panels -= scenes[scenes.length-1].duration;
    scenes[scenes.length-1].duration = 0;


    // Make space at the leftmost end of the chart for character names
    //var total_panels = parseInt(j['panels']);
    var panel_width = Math.min((width-longest_name)/total_panels, 15);
    var panel_shift = Math.round(longest_name/panel_width);
    total_panels += panel_shift;
    panel_width = Math.min(width/total_panels, 15);

    (function(x) {
      var i = 0;
      var xchars = Object.keys(x).map(function(c) {
        return {
          name: c,
          id: x[c],
          group: prefix.groups[c] || 1
        }
      });

      // Calculate chart height based on the number of characters
      // TODO: Redo this calculation
      //var raw_chart_height = xchars.length*(link_width + link_gap + group_gap);// - (link_gap + group_gap);
      var raw_chart_height = 360;
      var height = raw_chart_height - margin.top - margin.bottom;

      var svg = d3.select("#chart").append("svg")
	  .attr("width", width + margin.left + margin.right)
	  .attr("height", height + margin.top + margin.bottom)
          .attr("class", "chart")
          .attr("id", safe_name)
	  .append("g")
	  .attr("transform", "translate(" + margin.left + "," + margin.top + ")");


      var chars = [];
      var char_map = []; // maps id to pointer
      for (var i = 0; i < xchars.length; i++) {
	chars[chars.length] = new Character_(xchars[i].name, xchars[i].id, xchars[i].group);
	char_map[xchars[i].id] = chars[chars.length-1];
{'fraction_non_alphanumeric': 0.15482573726541554, 'fraction_numerical': 0.008425890463423975, 'mean_word_length': 2.9311253293187804, 'pattern_counts': {'":': 0, '<': 7, '<?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': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2401783', 'n_tokens_mistral': 3692, 'n_tokens_neox': 3508, 'n_words': 748}