<commit_before>var async           = require('async');
var util            = require('util');
var path            = require('path');
var EventEmitter    = require('events').EventEmitter;
var backend         = require('./backend');
var views           = require('./views');
var ReportManager   = require('./model/reportManager');
var Storage         = require('./storage');
var Cache           = require('./cache');
var message         = require('./widgets/message');
var prompt          = require('./widgets/prompt');
var ValidationError = require('./errors/validation');
var spawn           = require('child_process').spawn;

/**
 * Main Qissues application
 *
 * @param blessed.screen screen
 * @param object         options on invokation
 */
function Application(screen, options) {
  var app = this;
  var config;

  /**
   * Starts up the application
   * @param initial view
   */
  this.start = function(action, id) {
    setupKeyboard();
    screen.render();

    loadConfig(function(err, configStore) {
      config = configStore.serialize();

      app.storage  = new Storage(path.resolve(options.cwd, './.qi.json'));
      app.cache    = new Cache(app.storage);
      app.reports  = new ReportManager(app.storage);
      app.report   = app.reports.getDefault();
      app.filters  = app.reports.getDefault().getFilters();
      app.metadata = app.storage.get('metadata');

      app.report.on('change', function() {
        app.listIssues();
      });

      if(action) {
        app[action](id);
      } else {
        app.listIssues();
      }
    });
  };

  /**
   * Loads the config into the app
   * @param function done
   */
  var loadConfig = function(done) {
    var fields = ['hostname', 'username', 'password'];
    var configStore = new Storage(options.userConfig);

    async.eachSeries(fields, function(field, next) {
      if(configStore.get(field)) return next();

      prompt('Configuration: ' + field, screen, function(err, text) {
        if(err) return next(err);
        configStore.set(field, text);
        return next(null, text);
      });

    }, function(err) {
      if(err) return done(err);
      return done(null, configStore);
    });
  };

  /**
   * Sets up the global keyboard handlers
   */
  var setupKeyboard = function() {
    screen.key('C-c', function(ch, key) {
      return process.exit(0);
    });

    screen.key('?', function() {
      var opt = {
        stdio: 'inherit',
        env: process.env,
      };
      screen.exec('less', ['-c', 'docs/help.txt'], opt, function() {});
      screen.render();
    });

    screen.key('m', app.reloadMetadata);
  };

  /**
   * Lists all of the issues
   *
   * @param boolean invalidate
   */
  this.listIssues = function(invalidate, focus) {
    app.loading(invalidate ? 'Refreshing...' : null);

    var list = views.list(screen, app, !!invalidate, focus, function(done) {
      return backend.query(config, app.cache, app.report, !!invalidate, done);
    });

    list.on('select', function(num) {
      app.viewIssue(list.getSelected());
    });

    list.key('S-i', function() {
      prompt('Open Issue', screen, function(err, text) {
        app.viewIssue(text);
      });
    });

    list.key('c', function() {
      app.createIssue(app.report.getFilters());
    });
    list.key('S-c', function() {
      app.createIssue();
    });

    list.key('C-r', function() {
      app.listIssues(true, list.getSelected());
    });

    list.key('w', function() {
      var browser = config.browser || 'open';
      spawn(browser, [
        'https://' + config.hostname + '/issues/?jql=' + encodeURIComponent(app.filters.toJql())
      ]);
    });

    list.on('issue.change', function(change) {
      app.loading();
      backend.change(
        change.issue,
        change.changes,
        config,
        app.cache,
        function(err) {
          if(err) console.error(err);
          app.listIssues(true, change.issue);
        }
      );
    });

  };

  /**
   * Reloads the metadata and dumps it to stderr
   */
  this.reloadMetadata = function() {
    app.loading('Downloading metadata...');
    backend.metadata(config, function(err, data) {
      app.storage.set('metadata', data);
      message(screen, 'Done!');
    });
  };

  /**
   * View a single issue
   *
   * @param number num issue number
   * @param boolean invalidate
   */
  this.viewIssue = function(num, invalidate) {
    app.loading(invalidate ? 'Refreshing...' : '');

    backend.lookup(num, config, app.cache, invalidate, function(err, issue) {
      if(err) return app.emit('error', err);

      app.empty();
      var single = views.single(screen, issue, app);

      single.key(['escape', 'h'], function() {
        app.listIssues(null, num);
      });<commit_msg>redraw list after metadata<commit_after>var async           = require('async');
var util            = require('util');
var path            = require('path');
var EventEmitter    = require('events').EventEmitter;
var backend         = require('./backend');
var views           = require('./views');
var ReportManager   = require('./model/reportManager');
var Storage         = require('./storage');
var Cache           = require('./cache');
var message         = require('./widgets/message');
var prompt          = require('./widgets/prompt');
var ValidationError = require('./errors/validation');
var spawn           = require('child_process').spawn;

/**
 * Main Qissues application
 *
 * @param blessed.screen screen
 * @param object         options on invokation
 */
function Application(screen, options) {
  var app = this;
  var config;

  /**
   * Starts up the application
   * @param initial view
   */
  this.start = function(action, id) {
    setupKeyboard();
    screen.render();

    loadConfig(function(err, configStore) {
      config = configStore.serialize();

      app.storage  = new Storage(path.resolve(options.cwd, './.qi.json'));
      app.cache    = new Cache(app.storage);
      app.reports  = new ReportManager(app.storage);
      app.report   = app.reports.getDefault();
      app.filters  = app.reports.getDefault().getFilters();
      app.metadata = app.storage.get('metadata');

      app.report.on('change', function() {
        app.listIssues();
      });

      if(action) {
        app[action](id);
      } else {
        app.listIssues();
      }
    });
  };

  /**
   * Loads the config into the app
   * @param function done
   */
  var loadConfig = function(done) {
    var fields = ['hostname', 'username', 'password'];
    var configStore = new Storage(options.userConfig);

    async.eachSeries(fields, function(field, next) {
      if(configStore.get(field)) return next();

      prompt('Configuration: ' + field, screen, function(err, text) {
        if(err) return next(err);
        configStore.set(field, text);
        return next(null, text);
      });

    }, function(err) {
      if(err) return done(err);
      return done(null, configStore);
    });
  };

  /**
   * Sets up the global keyboard handlers
   */
  var setupKeyboard = function() {
    screen.key('C-c', function(ch, key) {
      return process.exit(0);
    });

    screen.key('?', function() {
      var opt = {
        stdio: 'inherit',
        env: process.env,
      };
      screen.exec('less', ['-c', 'docs/help.txt'], opt, function() {});
      screen.render();
    });

    screen.key('m', app.reloadMetadata);
  };

  /**
   * Lists all of the issues
   *
   * @param boolean invalidate
   */
  this.listIssues = function(invalidate, focus) {
    app.loading(invalidate ? 'Refreshing...' : null);

    var list = views.list(screen, app, !!invalidate, focus, function(done) {
      return backend.query(config, app.cache, app.report, !!invalidate, done);
    });

    list.on('select', function(num) {
      app.viewIssue(list.getSelected());
    });

    list.key('S-i', function() {
      prompt('Open Issue', screen, function(err, text) {
        app.viewIssue(text);
      });
    });

    list.key('c', function() {
      app.createIssue(app.report.getFilters());
    });
    list.key('S-c', function() {
      app.createIssue();
    });

    list.key('C-r', function() {
      app.listIssues(true, list.getSelected());
    });

    list.key('w', function() {
      var browser = config.browser || 'open';
      spawn(browser, [
        'https://' + config.hostname + '/issues/?jql=' + encodeURIComponent(app.filters.toJql())
      ]);
    });

    list.on('issue.change', function(change) {
      app.loading();
      backend.change(
        change.issue,
        change.changes,
        config,
        app.cache,
        function(err) {
          if(err) console.error(err);
          app.listIssues(true, change.issue);
        }
      );
    });

  };

  /**
   * Reloads the metadata and dumps it to stderr
   */
  this.reloadMetadata = function() {
    app.loading('Downloading metadata...');
    backend.metadata(config, function(err, data) {
      app.storage.set('metadata', data);
      message(screen, 'Done!');
      app.listIssues(true);
    });
  };

  /**
   * View a single issue
   *
   * @param number num issue number
   * @param boolean invalidate
   */
  this.viewIssue = function(num, invalidate) {
    app.loading(invalidate ? 'Refreshing...' : '');

    backend.lookup(num, config, app.cache, invalidate, function(err, issue) {
      if(err) return app.emit('error', err);

      app.empty();
      var single = views.single(screen, issue, app);

      single.key(['escape', 'h'], function() {
        app.listIssues(null, num);
      });
{'fraction_non_alphanumeric': 0.16675395412171362, 'fraction_numerical': 0.00020948989211270555, 'mean_word_length': 2.4469314079422384, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '282304', 'n_tokens_mistral': 2901, 'n_tokens_neox': 2842, 'n_words': 610}