<commit_before>(function() {
  var fs = require('fs'),
    path = require('path'),
    _ = require('underscore');

  var SelfReloadJSON = function SelfReloadJSON(options) {
    switch(typeof options) {
      case 'string': options = { fileName: options }; break;
      case 'object': break;
      default: return;
    }

    var updateFile, onFileChange, stop, resume, save;
    var content, updateFileLock, fileName, watcher;

    content = this;

    options = _.defaults(options, {
      fileName: '',
      encoding: 'utf8',
      additive: false,
      method: 'native',
      interval: 5000
    });

    content.stop = stop = function stop() {
      if(watcher) {
        if(typeof watcher === 'string')
          fs.unwatchFile(watcher, onFileChange);
        else
          watcher.close();
        watcher = null;
      }
    };

    content.resume = resume = function resume() {
      stop();
      options.fileName = path.resolve(options.fileName);
      fileName = path.basename(options.fileName);
      switch(options.method) {
        case 'native':
          watcher = fs.watch(options.fileName, {
            encoding: options.encoding
          }, onFileChange);
          break;
        case 'polling':
          watcher = options.fileName;
          fs.watchFile(options.fileName, {
            interval: options.interval
          }, onFileChange);
          break;
      }
      updateFile();
    };

    content.save = save = function save(opts) {
      if(!opts) opts = {};
      updateFileLock = true;
      try{
        fs.writeFileSync(options.fileName, JSON.stringify(content), _.extend({
          encoding: options.encoding
        }, opts));
      } finally {
        updateFileLock = false;
      }
    };

    onFileChange = function onFileChange(a, b) {
      if(a instanceof fs.Stats) {
        if(a.mtime === b.mtime) return;
        updateFile();
      } else {
        if(b !== fileName) return;
        updateFile();
      }
    };

    updateFile = function updateFile() {
      if(updateFileLock) return;
      updateFileLock = true;
      try {
        var rawFile = fs.readFileSync(options.fileName, {
          encoding: options.encoding
        });
        var newContent = JSON.parse(rawFile);
        if(!options.additive) {
          var removeList = _.keys(content)
          for(var i = 0, l = removeList.length; i < l; i++)
            delete content[removeList[i]];
          if(stop) content.stop = stop;
          if(resume) content.resume = resume;
        }
        _.extendOwn(content, newContent);
      } catch(err) {<commit_msg>Add more options<commit_after>(function() {
  var fs = require('fs'),
    path = require('path'),
    _ = require('underscore');

  var SelfReloadJSON = function SelfReloadJSON(options) {
    switch(typeof options) {
      case 'string': options = { fileName: options }; break;
      case 'object': case 'undefined': break;
      default: throw new Error('Invalid options type.');
    }

    var updateFile, onFileChange, stop, resume, save;
    var content, updateFileLock, fileName, watcher;

    content = this;

    options = _.defaults(options || {}, {
      fileName: '',
      encoding: 'utf8',
      additive: false,
      method: 'native',
      interval: 5000,
      reviver: null,
      replacer: null
    });

    content.stop = stop = function stop() {
      if(watcher) {
        if(typeof watcher === 'string')
          fs.unwatchFile(watcher, onFileChange);
        else
          watcher.close();
        watcher = null;
      }
    };

    content.resume = resume = function resume() {
      stop();
      options.fileName = path.resolve(options.fileName);
      fileName = path.basename(options.fileName);
      switch(options.method) {
        case 'native':
          watcher = fs.watch(options.fileName, {
            encoding: options.encoding
          }, onFileChange);
          break;
        case 'polling':
          watcher = options.fileName;
          fs.watchFile(options.fileName, {
            interval: options.interval
          }, onFileChange);
          break;
      }
      updateFile();
    };

    content.save = save = function save(opts) {
      opts = _.defaults(opts || {}, {
        encoding: options.encoding,
        replacer: options.replacer,
        space: null
      });
      updateFileLock = true;
      try {
        fs.writeFileSync(
          options.fileName,
          JSON.stringify(content, opts.replacer, opts.space),
          _.omit(opts, 'replacer', 'space')
        );
      } finally {
        updateFileLock = false;
      }
    };

    onFileChange = function onFileChange(a, b) {
      if(a instanceof fs.Stats) {
        if(a.mtime === b.mtime) return;
        updateFile();
      } else {
        if(b !== fileName) return;
        updateFile();
      }
    };

    updateFile = function updateFile() {
      if(updateFileLock) return;
      updateFileLock = true;
      try {
        var rawFile = fs.readFileSync(options.fileName, {
          encoding: options.encoding
        });
        var newContent = JSON.parse(rawFile, options.reviver);
        if(!options.additive) {
          var removeList = _.keys(content)
          for(var i = 0, l = removeList.length; i < l; i++)
            delete content[removeList[i]];
          if(stop) content.stop = stop;
          if(resume) content.resume = resume;
          if(save) content.save = save;
        }
        _.extendOwn(content, newContent);
      } catch(err) {
{'fraction_non_alphanumeric': 0.12543299908842298, 'fraction_numerical': 0.0021877848678213308, 'mean_word_length': 1.9961769524849808, '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': '3118554', 'n_tokens_mistral': 1570, 'n_tokens_neox': 1571, 'n_words': 350}