<commit_before>function Settings() {
  var self = this;

  this.loaded = false;
  this.moduleQueue = [];
  this.events = {};

  // Load the settings
  _.request(chrome.extension.getURL("defaults.json"), "GET", function (code) {
    var defaults = JSON.parse(code);
    self.tips = defaults.tips;

    self.defaults = JSON.parse(localStorage.getItem("hnspecial-defaults")); // Used when the version changes
    self.version = parseInt(localStorage.getItem("hnspecial-settings-version"));

    self.currentSettings = JSON.parse(localStorage.getItem("hnspecial-settings"));

    var added = []; // Tracks which features have been added in a settings version

    if (isNaN(self.version)) {
      self.version = defaults.settings_version;
      self.defaults = defaults.settings;
      self.currentSettings = _.clone(self.defaults);
    } else if (self.version < defaults.settings_version) {
      self.version = defaults.settings_version;

      // Rebuild the settings object from the defaults (respects the ordering)
      var old = self.currentSettings;
      self.defaults = defaults.settings;
      self.currentSettings = _.clone(self.defaults);
      added = Object.keys(self.currentSettings);

      for (var key in self.currentSettings) {
        if (old[key] !== undefined) {
          self.currentSettings[key] = old[key];
          added.splice(added.indexOf(key), 1); // Remove existing features from added
        }
      }
    }

    self.save();

    // Build the menu and launch the rest of the modules when the DOM is ready
    _.load(function () {
      self.buildMenu(added, defaults.requirements);
      self.loaded = true;
      self.moduleQueue.forEach(function (module) {
        self.runModule(module);
      });
    });
  });
}

Settings.prototype.save = function () {
  localStorage.setItem("hnspecial-defaults", JSON.stringify(this.defaults));
  localStorage.setItem("hnspecial-settings-version", this.version);
  localStorage.setItem("hnspecial-settings", JSON.stringify(this.currentSettings));
};

Settings.prototype.registerModule = function (key, callback) {
  var module = { key: key, callback: callback };

  if (!this.loaded) {
    this.moduleQueue.push(module);
  } else {
    this.runModule(module);
  }
};

Settings.prototype.runModule = function (module) {
  if (this.currentSettings[module.key]) module.callback();
};

Settings.prototype.subscribe = function (event, callback) {
  if (!this.events[event]) {
    this.events[event] = [];
  }
  this.events[event].push(callback);
};

Settings.prototype.emit = function (event) {
  if (this.events[event]) {
    this.events[event].forEach(function (callback) {
      callback();
    });
  }
};

Settings.prototype.buildMenu = function (added, requirements) {
  var self = this;
  var pageTop = _.$(".pagetop");
  var container = pageTop[1] || pageTop[0];

  if (container) {
    var items = this.buildMenuFrame(container, !added.length);

    if (container === pageTop[0]) items.button.classList.add("hnspecial-settings-container-cell");

    // Build the settings items
    var keys = Object.keys(this.currentSettings);
    var map = {};<commit_msg>add functionality to include data in events<commit_after>function Settings() {
  var self = this;

  this.loaded = false;
  this.moduleQueue = [];
  this.events = {};

  // Load the settings
  _.request(chrome.extension.getURL("defaults.json"), "GET", function (code) {
    var defaults = JSON.parse(code);
    self.tips = defaults.tips;

    self.defaults = JSON.parse(localStorage.getItem("hnspecial-defaults")); // Used when the version changes
    self.version = parseInt(localStorage.getItem("hnspecial-settings-version"));

    self.currentSettings = JSON.parse(localStorage.getItem("hnspecial-settings"));

    var added = []; // Tracks which features have been added in a settings version

    if (isNaN(self.version)) {
      self.version = defaults.settings_version;
      self.defaults = defaults.settings;
      self.currentSettings = _.clone(self.defaults);
    } else if (self.version < defaults.settings_version) {
      self.version = defaults.settings_version;

      // Rebuild the settings object from the defaults (respects the ordering)
      var old = self.currentSettings;
      self.defaults = defaults.settings;
      self.currentSettings = _.clone(self.defaults);
      added = Object.keys(self.currentSettings);

      for (var key in self.currentSettings) {
        if (old[key] !== undefined) {
          self.currentSettings[key] = old[key];
          added.splice(added.indexOf(key), 1); // Remove existing features from added
        }
      }
    }

    self.save();

    // Build the menu and launch the rest of the modules when the DOM is ready
    _.load(function () {
      self.buildMenu(added, defaults.requirements);
      self.loaded = true;
      self.moduleQueue.forEach(function (module) {
        self.runModule(module);
      });
    });
  });
}

Settings.prototype.save = function () {
  localStorage.setItem("hnspecial-defaults", JSON.stringify(this.defaults));
  localStorage.setItem("hnspecial-settings-version", this.version);
  localStorage.setItem("hnspecial-settings", JSON.stringify(this.currentSettings));
};

Settings.prototype.registerModule = function (key, callback) {
  var module = { key: key, callback: callback };

  if (!this.loaded) {
    this.moduleQueue.push(module);
  } else {
    this.runModule(module);
  }
};

Settings.prototype.runModule = function (module) {
  if (this.currentSettings[module.key]) module.callback();
};

Settings.prototype.subscribe = function (event, callback) {
  if (!this.events[event]) {
    this.events[event] = [];
  }
  this.events[event].push(callback);
};

Settings.prototype.emit = function (event, data) {
  if (this.events[event]) {
    this.events[event].forEach(function (callback) {
      callback(data);
    });
  }
};

Settings.prototype.buildMenu = function (added, requirements) {
  var self = this;
  var pageTop = _.$(".pagetop");
  var container = pageTop[1] || pageTop[0];

  if (container) {
    var items = this.buildMenuFrame(container, !added.length);

    if (container === pageTop[0]) items.button.classList.add("hnspecial-settings-container-cell");

    // Build the settings items
    var keys = Object.keys(this.currentSettings);
    var map = {};
{'fraction_non_alphanumeric': 0.1397082143989851, 'fraction_numerical': 0.0012686330478908975, 'mean_word_length': 3.447813822284908, 'pattern_counts': {'":': 0, '<': 5, '<?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': '7165637', 'n_tokens_mistral': 1851, 'n_tokens_neox': 1830, 'n_words': 399}