<commit_before>/*eslint-env node */
/*eslint no-sync: "off", global-require: "off"*/
'use strict';

var path = require('path')
  , basename = path.basename(__filename, '.js')
  , debug = require('debug')('ezmaster:' + basename)
  , bodyParser = require('body-parser')
  , fs = require('fs')
  , getSize = require('get-folder-size')
  , filesize = require('filesize')
  , Docker = require('dockerode')
  , docker = new Docker({ socketPath: '/var/run/docker.sock'})
  , exec = require('child_process').exec
  , jsonfile = require('jsonfile')
  , mkdirp = require('mkdirp')
  , rimraf = require('rimraf')
  , fileExists = require('file-exists')
  , instances = require('../helpers/instances');

// The bool to check if some modifications occured on one or multiple instances.
var instancesChangesBool = true;

jsonfile.spaces = 2;

module.exports = function (router, core) {

  router.route('/').get(function (req, res, next) {

    return res.render('template.html');

  });

  router.route('/-/v1/instances').get(function (req, res, next) {

    instances.getInstances(instancesChangesBool, function (err, data) {

      if (err) { return next(err); }

      debug(data);

      return res.status(200).send(data);

    });

  });

  router.route('/-/v1/instances/:containerId').put(bodyParser(), function (req, res, next) {
    var container = docker.getContainer(req.params.containerId);

    container.inspect(function (err, data) {
      if (err) { return next(err); }
      if (req.body.action == 'start' && data.State.Running == false) {
        container.start(function (err, datas, container) {
          if (err) { return next(err); }

          // When an instance is started, we call getInstances() to update the instances list cache.
          // instancesChangesBool set to true because we have to rebuild the list in getInstances().
          instancesChangesBool = true;
          instances.getInstances(instancesChangesBool, function (err, data) {
            if (err) { return next(err); }
          });
          // instancesChangesBool comes back to false because the cache is up to date.
          instancesChangesBool = false;

          res.status(200).send('Starting done');
        });
      }
      else if (req.body.action == 'stop' && data.State.Running == true) {
        container.stop(function (err, datas, container) {
          if (err) { return next(err); }

          // When an instance is stopped, we call getInstances() to update the instances list cache.
          // instancesChangesBool set to true because we have to rebuild the list in getInstances().
          instancesChangesBool = true;
          instances.getInstances(instancesChangesBool, function (err, data) {
            if (err) { return next(err); }
          });
          // instancesChangesBool comes back to false because the cache is up to date.
          instancesChangesBool = false;

          res.status(200).send('Stoping done');
        });
      }
      else if (req.body.action == 'updateConfig') {
        var splittedName = data.Name.split('/');

        jsonfile.writeFile(
          path.join(__dirname, '../instances/', splittedName[1], '/config/config.json'),
          req.body.newConfig, function (err) {

            if (err) { return next(err); }

            if (data.State.Running == true) {
              container.restart(function (err) {
                if (err) { return next(err); }
                res.status(200).send('Update done');
              });
            }
            else {
              res.status(200).send('Update done');
            }
          });

        // When a new config is given to an instance
        //we call getInstances() to update the instances list cache.
        // instancesChangesBool set to true because we have to rebuild the list in getInstances().
        instancesChangesBool = true;
        instances.getInstances(instancesChangesBool, function (err, data) {
          if (err) { return next(err); }
        });
        // instancesChangesBool comes back to false because the cache is up to date.
        instancesChangesBool = false;

      }
    });
  });

  router.route('/-/v1/instances/verif').get(bodyParser(), function (req, res, next) {
    if (fileExists(path.join(__dirname, '../manifests/'
      +req.query.technicalName+'.json')) == false) {
      res.status(200).send('Technical name does not exists');
    }
    else {
      res.status(409).send('Technical name '+req.query.technicalName+' already exists');
    }
  });

  router.route('/-/v1/instances/:containerId').get(bodyParser(), function (req, res, next) {
    var container = docker.getContainer(req.params.containerId);

    container.inspect(function (err, data) {
      if (err) { return next(err); }

      var splittedName = data.Name.split('/');

      if (req.query.action == 'info') {
        var directoryDatas = path.join(__dirname, '../instances/', splittedName[1], '/data/')
          , result = {};

        getSize(directoryDatas, function (err, size) {
          if (err) { return next(err); }

          result['technicalName'] = splittedName[1];
          result['size'] = filesize(size);

          return res.status(200).send(result);
        });
      }
      else if (req.query.action == 'config') {
        jsonfile.readFile(
        path.join(__dirname, '../instances/', splittedName[1], '/config/config.json'),
        function (err, obj) {

          if (err) { return next(err); }

          return res.status(200).send(obj);
        });
      }
    });
  });

  router.route('/-/v1/instances/:containerId').delete(function (req, res, next) {
    var container = docker.getContainer(req.params.containerId);

    container.inspect(function (err, data) {
      if (err) { return next(err); }

      if (data.State.Running == true) {
        container.stop(function (err, datas, cont) {
          if (err) { return next(err); }

          container.remove(function (err, datas, cont) {
            if (err) { return next(err); }
          });
        });
      }
      else if (data.State.Running == false) {
        container.remove(function (err, datas, cont) {
          if (err) { return next(err); }
        });
      }

      var splittedName = data.Name.split('/');
      rimraf(path.join(__dirname, '../instances/', splittedName[1]), function (err) {
        if (err) { return next(err); }

        rimraf(path.join(__dirname, '../manifests/', splittedName[1] + '.json'), function (err) {
          if (err) { return next(err); }

          res.status(200).send('Removing done');
        });
      });
    });

    // When an instance is deleted, we call getInstances() to update the instances list cache.
    // instancesChangesBool set to true because we have to rebuild the list in getInstances().
    instancesChangesBool = true;
    instances.getInstances(instancesChangesBool, function (err, data) {
      if (err) { return next(err); }
    });
    // instancesChangesBool comes back to false because the cache is up to date.
    instancesChangesBool = false;

  });

  router.route('/-/v1/instances').post(bodyParser(), function (req, res, next) {
    var technicalName = req.body.technicalName
      , longName = req.body.longName
      , image = req.body.app
      , project = req.body.project
      , study = req.body.study;

    if (/^[a-z0-9]+$/.test(project) == false && project != '' && project != null) {

      return res.status(400).send('Enter a valid project name');

    }
    if (/^[a-z0-9]+$/.test(study) == false && study != '' && study != null) {

      return res.status(400).send('Enter a valid study name');

    }
    if (fileExists(path.join(__dirname, '../manifests/'+req.query.technicalName+'.json')) == true) {

      res.status(409).send('Technical name already exists');

    }
    else {

      docker.pull(image, function (err, stream) {
        if (err) { return res.status(400).send(err); }

        docker.modem.followProgress(stream, onFinished);

        function onFinished(err, output) {
          if (err) { return res.status(400).send(err); }

          mkdirp(path.join(__dirname, '../instances/'+technicalName+'/config/'), function (err) {
            if (err) { return next(err); }

            mkdirp(path.join(__dirname, '../instances/'+technicalName+'/data/'), function (err) {
              if (err) { return next(err); }

              fs.appendFile(
              path.join(__dirname, '../instances/'+technicalName+'/config/config.json')
              , '{}', function (err) {

                if (err) { return next(err); }

                var instancesArray = fs.readdirSync(path.join(__dirname, '../instances/'));

                docker.listContainers({all : true}, function (err, containers) {
                  if (err) { return next(err); }

                  var portMax = 0
                    , freePortSplitted = process.env.EZMASTER_FREE_PORT_RANGE.split('-');

                  (function checkPort() {
                    var element = containers.pop();

                    if (element) {
                      var splittedName = element.Names[0].split('/');
                      if (instancesArray.indexOf(splittedName[1]) === -1) {
                        return checkPort();
                      }

                      var container = docker.getContainer(element.Id);

                      container.inspect(function (err, data) {
                        if (err) { return next(err); }

                        var keys =  Object.keys(data.HostConfig.PortBindings)
                          , currentPort = data.HostConfig.PortBindings[keys[0]][0].HostPort;

                        if (currentPort >= portMax) { portMax = parseInt(currentPort) + 1; }
                        return checkPort();
                      });
                    }
                    else {
                      debug(portMax);
                      if (!Number.isInteger(portMax) || portMax == 0) {
                        portMax = freePortSplitted[0];
                      }

                      var cmd = 'docker run -d -p '+portMax+':3000 ' +
                      '-e http_proxy -e https_proxy -e EZMASTER_MONGODB_HOST_PORT '+
                      '--net=ezmaster_default --link ezmaster_db '+
                      '-v '+process.env.EZMASTER_PATH+'/instances/'+
                      technicalName+'/config/config.json:'+'/opt/ezmaster/config/config.json '+
                      '-v '+process.env.EZMASTER_PATH+'/instances/'
                      +technicalName+'/data/:/opt/ezmaster/data/ '+
                      '--name '+technicalName+' '+image;

                      var newlongName = {
                        'longName' : longName
                      };
                      jsonfile.writeFile(
                        path.join(__dirname, '../manifests/'+technicalName+'.json')
                        , newlongName, function (err) {
                          if (err) { return next(err); }
                        });

                      exec(cmd, function (err, stdout, stderr) {
                        if (err) { return next(err); }

                        // When an instance is created, we call getInstances() to update the instances list cache.
                        // instancesChangesBool set to true because we have to rebuild the list in getInstances().
                        instancesChangesBool = true;
                        instances.getInstances(instancesChangesBool, function (err, data) {
                          if (err) { return next(err); }
                        });
                        // instancesChangesBool comes back to false because the cache is up to date.
                        instancesChangesBool = false;

                        return res.status(200).send('Instance created');
                      });
                    }
                  })();
                });
              });
            });
          });
        }
      });
    }
  });
};<commit_msg>Solving the useless cache update problem.<commit_after>/*eslint-env node */
/*eslint no-sync: "off", global-require: "off"*/
'use strict';

var path = require('path')
  , basename = path.basename(__filename, '.js')
  , debug = require('debug')('ezmaster:' + basename)
  , bodyParser = require('body-parser')
  , fs = require('fs')
  , getSize = require('get-folder-size')
  , filesize = require('filesize')
  , Docker = require('dockerode')
  , docker = new Docker({ socketPath: '/var/run/docker.sock'})
  , exec = require('child_process').exec
  , jsonfile = require('jsonfile')
  , mkdirp = require('mkdirp')
  , rimraf = require('rimraf')
  , fileExists = require('file-exists')
  , instances = require('../helpers/instances');

// The bool to check if some modifications occured on one or multiple instances.
var instancesChangesBool = true;

jsonfile.spaces = 2;

module.exports = function (router, core) {

  router.route('/').get(function (req, res, next) {

    return res.render('template.html');

  });

  router.route('/-/v1/instances').get(function (req, res, next) {

    instances.getInstances(instancesChangesBool, function (err, data) {

      if (err) { return next(err); }

      debug(data);

      return res.status(200).send(data);

    });

    // instancesChangesBool set to false because the cache is up to date.
    instancesChangesBool = false;

  });

  router.route('/-/v1/instances/:containerId').put(bodyParser(), function (req, res, next) {
    var container = docker.getContainer(req.params.containerId);

    container.inspect(function (err, data) {
      if (err) { return next(err); }
      if (req.body.action == 'start' && data.State.Running == false) {
        container.start(function (err, datas, container) {
          if (err) { return next(err); }

          // When an instance is started, we call getInstances() to update the instances list cache.
          // instancesChangesBool set to true because we have to rebuild the list in getInstances().
          instancesChangesBool = true;
          instances.getInstances(instancesChangesBool, function (err, data) {
            if (err) { return next(err); }
          });
          // instancesChangesBool comes back to false because the cache is up to date.
          instancesChangesBool = false;

          res.status(200).send('Starting done');
        });
      }
      else if (req.body.action == 'stop' && data.State.Running == true) {
        container.stop(function (err, datas, container) {
          if (err) { return next(err); }

          // When an instance is stopped, we call getInstances() to update the instances list cache.
          // instancesChangesBool set to true because we have to rebuild the list in getInstances().
          instancesChangesBool = true;
          instances.getInstances(instancesChangesBool, function (err, data) {
            if (err) { return next(err); }
          });
          // instancesChangesBool comes back to false because the cache is up to date.
          instancesChangesBool = false;

          res.status(200).send('Stoping done');
        });
      }
      else if (req.body.action == 'updateConfig') {
        var splittedName = data.Name.split('/');

        jsonfile.writeFile(
          path.join(__dirname, '../instances/', splittedName[1], '/config/config.json'),
          req.body.newConfig, function (err) {

            if (err) { return next(err); }

            if (data.State.Running == true) {
              container.restart(function (err) {
                if (err) { return next(err); }
                res.status(200).send('Update done');
              });
            }
            else {
              res.status(200).send('Update done');
            }
          });

        // When a new config is given to an instance
        //we call getInstances() to update the instances list cache.
        // instancesChangesBool set to true because we have to rebuild the list in getInstances().
        instancesChangesBool = true;
        instances.getInstances(instancesChangesBool, function (err, data) {
          if (err) { return next(err); }
        });
        // instancesChangesBool comes back to false because the cache is up to date.
        instancesChangesBool = false;

      }
    });
  });

  router.route('/-/v1/instances/verif').get(bodyParser(), function (req, res, next) {
    if (fileExists(path.join(__dirname, '../manifests/'
      +req.query.technicalName+'.json')) == false) {
      res.status(200).send('Technical name does not exists');
    }
    else {
      res.status(409).send('Technical name '+req.query.technicalName+' already exists');
    }
  });

  router.route('/-/v1/instances/:containerId').get(bodyParser(), function (req, res, next) {
    var container = docker.getContainer(req.params.containerId);

    container.inspect(function (err, data) {
      if (err) { return next(err); }

      var splittedName = data.Name.split('/');

      if (req.query.action == 'info') {
        var directoryDatas = path.join(__dirname, '../instances/', splittedName[1], '/data/')
          , result = {};

        getSize(directoryDatas, function (err, size) {
          if (err) { return next(err); }

          result['technicalName'] = splittedName[1];
          result['size'] = filesize(size);

          return res.status(200).send(result);
        });
      }
      else if (req.query.action == 'config') {
        jsonfile.readFile(
        path.join(__dirname, '../instances/', splittedName[1], '/config/config.json'),
        function (err, obj) {

          if (err) { return next(err); }

          return res.status(200).send(obj);
        });
      }
    });
  });

  router.route('/-/v1/instances/:containerId').delete(function (req, res, next) {
    var container = docker.getContainer(req.params.containerId);

    container.inspect(function (err, data) {
      if (err) { return next(err); }

      if (data.State.Running == true) {
        container.stop(function (err, datas, cont) {
          if (err) { return next(err); }

          container.remove(function (err, datas, cont) {
            if (err) { return next(err); }
          });
        });
      }
      else if (data.State.Running == false) {
        container.remove(function (err, datas, cont) {
          if (err) { return next(err); }
        });
      }

      var splittedName = data.Name.split('/');
      rimraf(path.join(__dirname, '../instances/', splittedName[1]), function (err) {
        if (err) { return next(err); }

        rimraf(path.join(__dirname, '../manifests/', splittedName[1] + '.json'), function (err) {
          if (err) { return next(err); }

          res.status(200).send('Removing done');
        });
      });
    });

    // When an instance is deleted, we call getInstances() to update the instances list cache.
    // instancesChangesBool set to true because we have to rebuild the list in getInstances().
    instancesChangesBool = true;
    instances.getInstances(instancesChangesBool, function (err, data) {
      if (err) { return next(err); }
    });
    // instancesChangesBool comes back to false because the cache is up to date.
    instancesChangesBool = false;

  });

  router.route('/-/v1/instances').post(bodyParser(), function (req, res, next) {
    var technicalName = req.body.technicalName
      , longName = req.body.longName
      , image = req.body.app
      , project = req.body.project
      , study = req.body.study;

    if (/^[a-z0-9]+$/.test(project) == false && project != '' && project != null) {

      return res.status(400).send('Enter a valid project name');

    }
    if (/^[a-z0-9]+$/.test(study) == false && study != '' && study != null) {

      return res.status(400).send('Enter a valid study name');

    }
    if (fileExists(path.join(__dirname, '../manifests/'+req.query.technicalName+'.json')) == true) {

      res.status(409).send('Technical name already exists');

    }
    else {

      docker.pull(image, function (err, stream) {
        if (err) { return res.status(400).send(err); }

        docker.modem.followProgress(stream, onFinished);

        function onFinished(err, output) {
          if (err) { return res.status(400).send(err); }

          mkdirp(path.join(__dirname, '../instances/'+technicalName+'/config/'), function (err) {
            if (err) { return next(err); }

            mkdirp(path.join(__dirname, '../instances/'+technicalName+'/data/'), function (err) {
              if (err) { return next(err); }

              fs.appendFile(
              path.join(__dirname, '../instances/'+technicalName+'/config/config.json')
              , '{}', function (err) {

                if (err) { return next(err); }

                var instancesArray = fs.readdirSync(path.join(__dirname, '../instances/'));

                docker.listContainers({all : true}, function (err, containers) {
                  if (err) { return next(err); }

                  var portMax = 0
                    , freePortSplitted = process.env.EZMASTER_FREE_PORT_RANGE.split('-');

                  (function checkPort() {
                    var element = containers.pop();

                    if (element) {
                      var splittedName = element.Names[0].split('/');
                      if (instancesArray.indexOf(splittedName[1]) === -1) {
                        return checkPort();
                      }

                      var container = docker.getContainer(element.Id);

                      container.inspect(function (err, data) {
                        if (err) { return next(err); }

                        var keys =  Object.keys(data.HostConfig.PortBindings)
                          , currentPort = data.HostConfig.PortBindings[keys[0]][0].HostPort;

                        if (currentPort >= portMax) { portMax = parseInt(currentPort) + 1; }
                        return checkPort();
                      });
                    }
                    else {
                      debug(portMax);
                      if (!Number.isInteger(portMax) || portMax == 0) {
                        portMax = freePortSplitted[0];
                      }

                      var cmd = 'docker run -d -p '+portMax+':3000 ' +
                      '-e http_proxy -e https_proxy -e EZMASTER_MONGODB_HOST_PORT '+
                      '--net=ezmaster_default --link ezmaster_db '+
                      '-v '+process.env.EZMASTER_PATH+'/instances/'+
                      technicalName+'/config/config.json:'+'/opt/ezmaster/config/config.json '+
                      '-v '+process.env.EZMASTER_PATH+'/instances/'
                      +technicalName+'/data/:/opt/ezmaster/data/ '+
                      '--name '+technicalName+' '+image;

                      var newlongName = {
                        'longName' : longName
                      };
                      jsonfile.writeFile(
                        path.join(__dirname, '../manifests/'+technicalName+'.json')
                        , newlongName, function (err) {
                          if (err) { return next(err); }
                        });

                      exec(cmd, function (err, stdout, stderr) {
                        if (err) { return next(err); }

                        // When an instance is created, we call getInstances() to update the instances list cache.
                        // instancesChangesBool set to true because we have to rebuild the list in getInstances().
                        instancesChangesBool = true;
                        instances.getInstances(instancesChangesBool, function (err, data) {
                          if (err) { return next(err); }
                        });
                        // instancesChangesBool comes back to false because the cache is up to date.
                        instancesChangesBool = false;

                        return res.status(200).send('Instance created');
                      });
                    }
                  })();
                });
              });
            });
          });
        }
      });
    }
  });
};<|endoftext|>


<commit_before>// Handles login, logout, and obtaining current user session object.
// Uses Passport node package.

var express = require('express');
var MongoStore = require('connect-mongo')(express);
var User = require('../../models/user');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var config = require('../../config/secrets').get();
var database = require('../../lib/database.js');
var _ = require('underscore');

module.exports = function(app) {
  app = app || express();
  var auth = {};

  // Configure session storage
  auth.key = 'connect.sid';
  auth.stubKey = 'aggie.auth';
  auth.stubCookie = { path: '/', httpOnly: true, maxAge: 864e9 };

  // Old library version uses mongoose_connection rather than mongooseConnection
  auth.store = new MongoStore({ mongoose_connection: database.mongoose.connection });
  auth.secret = config.secret;
  auth.session = express.session({
    key: auth.key,
    secret: auth.secret,
    store: auth.store,
    cookie: auth.stubCookie
  });
  auth.session.key = auth.key;
  auth.adminParty = config.adminParty;

  // Passport session setup.
  //   To support persistent login sessions, Passport needs to be able to
  //   serialize users into and deserialize users out of the session.  Typically,
  //   this will be as simple as storing the user ID when serializing, and finding
  //   the user by ID when deserializing.
  passport.serializeUser(function(user, done) {
    done(null, user._id);
  });

  passport.deserializeUser(function(id, done) {
    User.findById(id, function(err, user) {
      done(err, user ? user.toJSON() : {});
    });
  });

  // Use the LocalStrategy within Passport
  //   Strategies in passport require a `verify` function, which accept
  //   credentials (in this case, a username and password), and invoke a callback
  //   with a user object.
  passport.use(new LocalStrategy(function(username, password, done) {
    User.findOne({ username: username }, function(err, user) {
      if (err) return done(err);
      if (!user) return done(null, false, { message: 'Unknown user ' + username });
      user.comparePassword(password, function(err, isMatch) {
        if (err) return done(err);
        if (isMatch) return done(null, user.toJSON());
        return done(null, false, { message: 'Invalid password' });
      });
    });
  }));

  // Configure Express
  app.use(express.urlencoded());
  app.use(express.json());
  app.use(express.cookieParser());
  app.use(express.methodOverride());
  app.use(auth.session);

  // Initialize Passport. Also use passport.session() middleware, to support
  // persistent login sessions.
  app.use(passport.initialize());
  app.use(passport.session());
  app.use(app.router);

  // Passively instantiate the session via cookie in request
  app.use(function(req, res, next) {
    if ((req.session && req.session.user) || auth.adminParty) {
      res.cookie(auth.stubKey, 'yes', auth.stubCookie);
    } else {
      res.cookie(auth.stubKey, 'no', auth.stubCookie);
    }
    auth.session(req, res, next);
  });

  function sessionStatus(req, res, next) {
    if (req.session.user) {
      // Keep the session fresh
      req.session.touch();
      res.cookie(auth.stubKey, 'yes', auth.stubCookie);
      res.send(200, _.omit(req.session.user, 'password'));
    } else {
      // There's no user object, so we'll just destroy the session
      res.cookie(auth.key, '', _.defaults({ maxAge: -864e9 }, req.session.cookie));
      res.cookie(auth.stubKey, 'no', auth.stubCookie);
      req.session.destroy(function(err) {
        if (err) return next(err);
        res.send(200, {});
      });
    }
  }

  // Use passport.authenticate() as route middleware to authenticate the request
  app.post('/login', function(req, res, next) {
    passport.authenticate('local', function(err, user, info) {
      if (err) return next(err);
      if (!user) {
        req.session.messages = [info.message];
        return res.send(403, info.message);
      }
      req.logIn(user, function(err) {
        if (err) return next(err);
        // Store user object in session
        req.session.user = _.clone(req.user);
        sessionStatus(req, res, next);
      });
    })(req, res, next);
  });

  // Log the user out
  app.get('/logout', function(req, res, next) {
    req.logout();
    delete req.session.user;
    // The cookie will be deleted by `sessionStatus()`
    sessionStatus(req, res, next);
  });

  // Return the currently logged-in user object
  app.get('/session', sessionStatus.bind(this));

  // Simple route middleware to ensure user is authenticated.
  //   Use this route middleware on any resource that needs to be protected.  If
  //   the request is authenticated (typically via a persistent login session),
  //   the request will proceed.
  auth.ensureAuthenticated = function(req, res, next) {
    // Verify if user is authenticated
    if (auth.adminParty || req.skipAuthentication || req.isAuthenticated()) {
      return next();
    }
    res.send(403);
  };

  // Use this route middleware on any resource that is public, so that it
  // skips the above authentication, as by default all API routes are to be
  // authenticated.
  auth.skipAuthentication = function(req, res, next) {
    req.skipAuthentication = true;
    return next();
  };

  return auth;
};
<commit_msg>Revert "revert to Mongoose 3.8"<commit_after>// Handles login, logout, and obtaining current user session object.
// Uses Passport node package.

var express = require('express');
var MongoStore = require('connect-mongo')(express);
var User = require('../../models/user');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var config = require('../../config/secrets').get();
var database = require('../../lib/database.js');
var _ = require('underscore');

module.exports = function(app) {
  app = app || express();
  var auth = {};

  // Configure session storage
  auth.key = 'connect.sid';
  auth.stubKey = 'aggie.auth';
  auth.stubCookie = { path: '/', httpOnly: true, maxAge: 864e9 };

  // Old library version uses mongoose_connection rather than mongooseConnection
  auth.store = new MongoStore({ mongooseConnection: database.mongoose.connection });
  auth.secret = config.secret;
  auth.session = express.session({
    key: auth.key,
    secret: auth.secret,
    store: auth.store,
    cookie: auth.stubCookie
  });
  auth.session.key = auth.key;
  auth.adminParty = config.adminParty;

  // Passport session setup.
  //   To support persistent login sessions, Passport needs to be able to
  //   serialize users into and deserialize users out of the session.  Typically,
  //   this will be as simple as storing the user ID when serializing, and finding
  //   the user by ID when deserializing.
  passport.serializeUser(function(user, done) {
    done(null, user._id);
  });

  passport.deserializeUser(function(id, done) {
    User.findById(id, function(err, user) {
      done(err, user ? user.toJSON() : {});
    });
  });

  // Use the LocalStrategy within Passport
  //   Strategies in passport require a `verify` function, which accept
  //   credentials (in this case, a username and password), and invoke a callback
  //   with a user object.
  passport.use(new LocalStrategy(function(username, password, done) {
    User.findOne({ username: username }, function(err, user) {
      if (err) return done(err);
      if (!user) return done(null, false, { message: 'Unknown user ' + username });
      user.comparePassword(password, function(err, isMatch) {
        if (err) return done(err);
        if (isMatch) return done(null, user.toJSON());
        return done(null, false, { message: 'Invalid password' });
      });
    });
  }));

  // Configure Express
  app.use(express.urlencoded());
  app.use(express.json());
  app.use(express.cookieParser());
  app.use(express.methodOverride());
  app.use(auth.session);

  // Initialize Passport. Also use passport.session() middleware, to support
  // persistent login sessions.
  app.use(passport.initialize());
  app.use(passport.session());
  app.use(app.router);

  // Passively instantiate the session via cookie in request
  app.use(function(req, res, next) {
    if ((req.session && req.session.user) || auth.adminParty) {
      res.cookie(auth.stubKey, 'yes', auth.stubCookie);
    } else {
      res.cookie(auth.stubKey, 'no', auth.stubCookie);
    }
    auth.session(req, res, next);
  });

  function sessionStatus(req, res, next) {
    if (req.session.user) {
      // Keep the session fresh
      req.session.touch();
      res.cookie(auth.stubKey, 'yes', auth.stubCookie);
      res.send(200, _.omit(req.session.user, 'password'));
    } else {
      // There's no user object, so we'll just destroy the session
      res.cookie(auth.key, '', _.defaults({ maxAge: -864e9 }, req.session.cookie));
      res.cookie(auth.stubKey, 'no', auth.stubCookie);
      req.session.destroy(function(err) {
        if (err) return next(err);
        res.send(200, {});
      });
    }
  }

  // Use passport.authenticate() as route middleware to authenticate the request
  app.post('/login', function(req, res, next) {
    passport.authenticate('local', function(err, user, info) {
      if (err) return next(err);
      if (!user) {
        req.session.messages = [info.message];
        return res.send(403, info.message);
      }
      req.logIn(user, function(err) {
        if (err) return next(err);
        // Store user object in session
        req.session.user = _.clone(req.user);
        sessionStatus(req, res, next);
      });
    })(req, res, next);
  });

  // Log the user out
  app.get('/logout', function(req, res, next) {
    req.logout();
    delete req.session.user;
    // The cookie will be deleted by `sessionStatus()`
    sessionStatus(req, res, next);
  });

  // Return the currently logged-in user object
  app.get('/session', sessionStatus.bind(this));

  // Simple route middleware to ensure user is authenticated.
  //   Use this route middleware on any resource that needs to be protected.  If
  //   the request is authenticated (typically via a persistent login session),
  //   the request will proceed.
  auth.ensureAuthenticated = function(req, res, next) {
    // Verify if user is authenticated
    if (auth.adminParty || req.skipAuthentication || req.isAuthenticated()) {
      return next();
    }
    res.send(403);
  };

  // Use this route middleware on any resource that is public, so that it
  // skips the above authentication, as by default all API routes are to be
  // authenticated.
  auth.skipAuthentication = function(req, res, next) {
    req.skipAuthentication = true;
    return next();
  };

  return auth;
};
<|endoftext|>


<commit_before>/*
 * grunt-bootstrap-json2less
 * https://github.com/rmulder/bootstrap-json2less
 *
 * Copyright (c) 2015 Robert Mulder
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {

  // Please see the Grunt documentation for more information regarding task
  // creation: http://gruntjs.com/creating-tasks

  grunt.registerMultiTask('bootstrap_json2less', 'Convert a Bootstrap config.json file to variables.less', function() {
    // Merge task-specific and/or target-specific options with these defaults.
    var shell = require('shelljs');
    var options = this.options({
      dist: null, //distribution folder. Leave blank for same folder
      varPrefix: '',// set to '@' if not included in config.json
      banner: '// DO NOT EDIT! GENERATED AUTOMATICALLY with grunt-bootstrap-json2less'
    });

    function removeExtension(file) {
      var result = file.split(".");
      return result = result[0];
    }

    this.files.forEach(function (file) {
      // parse, eval and save less variables
      file.src.forEach(function (src) {
        var key, search, replace, content, inputContent, lessContent, outputFile = file.dest;
        //lessContent = grunt.file.read(outputFile);
        //console.log('lessContent:', lessContent);
        inputContent = grunt.file.read(src);
        content = JSON.parse(inputContent);

        //console.log('===== this is the output of var content: ', content);
        if (content.vars) {
          for (key in content.vars) {
            //lessContent += options.varPrefix + removeExtension(key.replace(/\\/g, "_"))+ ': "'+key+'";\n';
            search = options.varPrefix + removeExtension(key.replace(/\\/g, "_")) + ':';
            replace = search + ' ' + content.vars[key]+';\n';
            //lessContent += options.varPrefix + removeExtension(key.replace(/\\/g, "_"))+ ': '+content.vars[key]+';\n';
            console.log('key:', key, 'value:', content.vars[key]);

            //^(\@brand-primary:)(\s+.+;)(.+)
            shell.sed('-i', '^(\\'+key+':)(\\s+.+;)(.+)', '\\1'+content.vars[key]+'\\3', file.dest);
/*
            var re1 = /^(\@brand-primary:)(\s+.+;)/ig;
            var re2 = /^(\@brand-primary:)(\s+.+;)/ig;
            //    return new RegExp('^' + matcher + '$');
            //         regex = new RegExp('^' + regex + '$');
//      regex = new RegExp('\\b' +  '(' + value.split(' ').join('|') + ')', 'i');
//  return string.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1');
//    var source = '(?:' + _.keys(map).join('|') + ')';

            var expression1 = '^(\\', expression2 = ':)(\\s+.+;)';
            //var regex = new RegExp(expression1 + key + expression2, 'gi');
            var regex = new RegExp('^(\\' + key + ':)(\\s+.+;)','gi');

            //var matches = lessContent.match(/'^\@('+key+':)(\s+.+;)'/gi);
            var matches = lessContent.match(regex);
            console.log('regex:', regex, 'matches:', matches);
            if (matches !== null) {
              console.log('matches:', matches);
            }
*/
            //lessContent.replace(/'^\@('+key+':)(\s+.+;)'/ig, '');
          }
        }

        /*if (options.banner) {
          lessContent = grunt.file.read(outputFile);
          lessContent = [options.banner, lessContent].join('\n');
          grunt.file.write(outputFile, lessContent);
        } */
        grunt.log.ok('%s succesfully updated!', outputFile);
        if (options.dist) {
          shell.cp('-f', file.dest, options.dist);
          grunt.log.ok('succesfully copied: %s to: %s', file.dest, options.dist);
        }
      });
    });
  });

};
<commit_msg>remove comment<commit_after>/*
 * grunt-bootstrap-json2less
 * https://github.com/rmulder/bootstrap-json2less
 *
 * Copyright (c) 2015 Robert Mulder
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {

  // Please see the Grunt documentation for more information regarding task
  // creation: http://gruntjs.com/creating-tasks

  grunt.registerMultiTask('bootstrap_json2less', 'Convert a Bootstrap config.json file to variables.less', function() {
    // Merge task-specific and/or target-specific options with these defaults.
    var shell = require('shelljs');
    var options = this.options({
      dist: null, //distribution folder. Leave blank for same folder
      varPrefix: '',// set to '@' if not included in config.json
      banner: '// DO NOT EDIT! GENERATED AUTOMATICALLY with grunt-bootstrap-json2less'
    });

    function removeExtension(file) {
      var result = file.split(".");
      return result = result[0];
    }

    this.files.forEach(function (file) {
      // parse, eval and save less variables
      file.src.forEach(function (src) {
        var key, search, replace, content, inputContent, lessContent, outputFile = file.dest;
        //lessContent = grunt.file.read(outputFile);
        //console.log('lessContent:', lessContent);
        inputContent = grunt.file.read(src);
        content = JSON.parse(inputContent);

        //console.log('===== this is the output of var content: ', content);
        if (content.vars) {
          for (key in content.vars) {
            //lessContent += options.varPrefix + removeExtension(key.replace(/\\/g, "_"))+ ': "'+key+'";\n';
            search = options.varPrefix + removeExtension(key.replace(/\\/g, "_")) + ':';
            replace = search + ' ' + content.vars[key]+';\n';
            //lessContent += options.varPrefix + removeExtension(key.replace(/\\/g, "_"))+ ': '+content.vars[key]+';\n';
            //console.log('key:', key, 'value:', content.vars[key]);

            //^(\@brand-primary:)(\s+.+;)(.+)
            shell.sed('-i', '^(\\'+key+':)(\\s+.+;)(.+)', '\\1'+content.vars[key]+'\\3', file.dest);
/*
            var re1 = /^(\@brand-primary:)(\s+.+;)/ig;
            var re2 = /^(\@brand-primary:)(\s+.+;)/ig;
            //    return new RegExp('^' + matcher + '$');
            //         regex = new RegExp('^' + regex + '$');
//      regex = new RegExp('\\b' +  '(' + value.split(' ').join('|') + ')', 'i');
//  return string.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1');
//    var source = '(?:' + _.keys(map).join('|') + ')';

            var expression1 = '^(\\', expression2 = ':)(\\s+.+;)';
            //var regex = new RegExp(expression1 + key + expression2, 'gi');
            var regex = new RegExp('^(\\' + key + ':)(\\s+.+;)','gi');

            //var matches = lessContent.match(/'^\@('+key+':)(\s+.+;)'/gi);
            var matches = lessContent.match(regex);
            console.log('regex:', regex, 'matches:', matches);
            if (matches !== null) {
              console.log('matches:', matches);
            }
*/
            //lessContent.replace(/'^\@('+key+':)(\s+.+;)'/ig, '');
          }
        }

        /*if (options.banner) {
          lessContent = grunt.file.read(outputFile);
          lessContent = [options.banner, lessContent].join('\n');
          grunt.file.write(outputFile, lessContent);
        } */
        grunt.log.ok('%s succesfully updated!', outputFile);
        if (options.dist) {
          shell.cp('-f', file.dest, options.dist);
          grunt.log.ok('succesfully copied: %s to: %s', file.dest, options.dist);
        }
      });
    });
  });

};
<|endoftext|>


<commit_before>/*
 * detect-dependencies.js
 * https://github.com/stephenplusplus/bower-install
 *
 * Copyright (c) 2013 Stephen Sawchuk
 * Licensed under the MIT license.
 */

var grunt = require('grunt');
var path = require('path');

var _ = grunt.util._;
var is = require('./helpers').is;
var isFile = grunt.file.isFile;

/**
 * Find the component's JSON configuration file.
 *
 * @param  {object} BI         the global configuration object
 * @param  {string} component  the name of the component to dig for
 * @return {object} the component's config file
 */
var findComponentConfigFile = function (BI, component) {
  var componentConfigFile;

  _.each(['bower.json', 'component.json', 'package.json'], function (configFile) {
    configFile = path.join(BI.get('directory'), component, configFile);

    if (!is(componentConfigFile, 'object') && isFile(configFile)) {
      componentConfigFile = grunt.file.readJSON(configFile);
    }
  });

  return componentConfigFile;
};

/**
 * Find the main script the component refers to. It's not always main :(
 *
 * @param  {object} BI            the global configuration object
 * @param  {string} component     the name of the component to dig for
 * @param  {componentConfigFile}  the component's config file
 * @return {string} the path to the component's primary script
 */
var findMainScript = function (BI, component, componentConfigFile) {
  var scriptPath;

  if (is(componentConfigFile.main, 'string')) {
    // start by looking for what every component should have: config.main
    scriptPath = componentConfigFile.main;
  } else if (is(componentConfigFile.main, 'array')) {
    // in case config.main is an array, grab the first one (grab all instead?)
    scriptPath = componentConfigFile.main[0];
  } else if (is(componentConfigFile.scripts, 'array')) {
    // still haven't found it. is it stored in config.scripts, then?
    scriptPath = componentConfigFile.scripts[0];
  }

  if (is(scriptPath, 'string')) {
    scriptPath = path.join(BI.get('directory'), component, scriptPath);
  }

  return scriptPath;
};

/**
 * Store the information our prioritizer will need to determine rank.
 *
 * @param  {object} BI       the global configuration object
 * @param  {object} options  optional parameters
 * @return {function} the iterator function, called on every component
 */
var gatherInfo = function (BI, options) {
  /**
   * The iterator function, which is called on each component.
   *
   * @param  {string} version    the version of the component
   * @param  {string} component  the name of the component
   * @return {undefined}
   */
  return function (version, component) {
    var dep = BI.get('global-dependencies').get(component) || {
      main: '',
      dependencies: {}
    };

    var componentConfigFile = findComponentConfigFile(BI, component);

    if (is(dep.dependents, 'number')) {
      dep.dependents += 1;
    } else {
      dep.dependents = 1;
    }

    dep.main = findMainScript(BI, component, componentConfigFile);

    if (!is(dep.main, 'string')) {
      // can't find the main file. this config file is useless!
      var warnings = BI.get('warnings');

      warnings.push(component + ' was not injected in your HTML.');
      warnings.push('Please go take a look in "' + path.join(BI.get('directory'), component) + '" for the file you need, then manually include it in your HTML file **outside** of the <!-- bower --> block.');

      BI.set('warnings', warnings);
      return;
    }

    if (options.nestedDependencies && componentConfigFile.dependencies) {
      var gatherInfoAgain = gatherInfo(BI, { nestedDependencies: false });

      dep.dependencies = componentConfigFile.dependencies;

      _.each(componentConfigFile.dependencies, function (version, component) {
        gatherInfoAgain(version, component);
      });
    }

    BI.get('global-dependencies').set(component, dep);
  }
};

/**
 * Sort the dependencies in the order we can best determine they're needed.
 *
 * @param  {object} BI  the global configuration object
 * @return {array} the sorted items of 'path/to/main/files.js'
 */
var prioritizeDependencies = function (BI) {
  var grouped = _.groupBy(BI.get('global-dependencies').get(), 'dependents');
  var sorted = [];

  _.each(grouped, function (dependencies, index) {
    _.chain(dependencies).groupBy(function (dependency) {
      return _.size(dependency.dependencies);
    }).toArray().value().reverse().forEach(function (dependency) {
      _.each(dependency, function (dependency) {
        sorted.push(dependency.main);
      });
    });
  });

  return sorted.reverse();
};

/**
 * Detect dependencies of the components from `bower.json`.
 *
 * @param  {object} BI the global configuration object.
 * @return {object} BI
 */
module.exports.detect = function (BI) {
  _.each(BI.get('bower.json').dependencies, gatherInfo(BI, { nestedDependencies: true }));

  BI.set('global-dependencies-sorted', prioritizeDependencies(BI));

  return BI;
};
<commit_msg>prefer new .bower.json file.<commit_after>/*
 * detect-dependencies.js
 * https://github.com/stephenplusplus/bower-install
 *
 * Copyright (c) 2013 Stephen Sawchuk
 * Licensed under the MIT license.
 */

var grunt = require('grunt');
var path = require('path');

var _ = grunt.util._;
var is = require('./helpers').is;
var isFile = grunt.file.isFile;

/**
 * Find the component's JSON configuration file.
 *
 * @param  {object} BI         the global configuration object
 * @param  {string} component  the name of the component to dig for
 * @return {object} the component's config file
 */
var findComponentConfigFile = function (BI, component) {
  var componentConfigFile;

  _.each(['.bower.json', 'bower.json', 'component.json', 'package.json'], function (configFile) {
    configFile = path.join(BI.get('directory'), component, configFile);

    if (!is(componentConfigFile, 'object') && isFile(configFile)) {
      componentConfigFile = grunt.file.readJSON(configFile);
    }
  });

  return componentConfigFile;
};

/**
 * Find the main script the component refers to. It's not always main :(
 *
 * @param  {object} BI            the global configuration object
 * @param  {string} component     the name of the component to dig for
 * @param  {componentConfigFile}  the component's config file
 * @return {string} the path to the component's primary script
 */
var findMainScript = function (BI, component, componentConfigFile) {
  var scriptPath;

  if (is(componentConfigFile.main, 'string')) {
    // start by looking for what every component should have: config.main
    scriptPath = componentConfigFile.main;
  } else if (is(componentConfigFile.main, 'array')) {
    // in case config.main is an array, grab the first one (grab all instead?)
    scriptPath = componentConfigFile.main[0];
  } else if (is(componentConfigFile.scripts, 'array')) {
    // still haven't found it. is it stored in config.scripts, then?
    scriptPath = componentConfigFile.scripts[0];
  }

  if (is(scriptPath, 'string')) {
    scriptPath = path.join(BI.get('directory'), component, scriptPath);
  }

  return scriptPath;
};

/**
 * Store the information our prioritizer will need to determine rank.
 *
 * @param  {object} BI       the global configuration object
 * @param  {object} options  optional parameters
 * @return {function} the iterator function, called on every component
 */
var gatherInfo = function (BI, options) {
  /**
   * The iterator function, which is called on each component.
   *
   * @param  {string} version    the version of the component
   * @param  {string} component  the name of the component
   * @return {undefined}
   */
  return function (version, component) {
    var dep = BI.get('global-dependencies').get(component) || {
      main: '',
      dependencies: {}
    };

    var componentConfigFile = findComponentConfigFile(BI, component);

    if (is(dep.dependents, 'number')) {
      dep.dependents += 1;
    } else {
      dep.dependents = 1;
    }

    dep.main = findMainScript(BI, component, componentConfigFile);

    if (!is(dep.main, 'string')) {
      // can't find the main file. this config file is useless!
      var warnings = BI.get('warnings');

      warnings.push(component + ' was not injected in your HTML.');
      warnings.push('Please go take a look in "' + path.join(BI.get('directory'), component) + '" for the file you need, then manually include it in your HTML file **outside** of the <!-- bower --> block.');

      BI.set('warnings', warnings);
      return;
    }

    if (options.nestedDependencies && componentConfigFile.dependencies) {
      var gatherInfoAgain = gatherInfo(BI, { nestedDependencies: false });

      dep.dependencies = componentConfigFile.dependencies;

      _.each(componentConfigFile.dependencies, function (version, component) {
        gatherInfoAgain(version, component);
      });
    }

    BI.get('global-dependencies').set(component, dep);
  }
};

/**
 * Sort the dependencies in the order we can best determine they're needed.
 *
 * @param  {object} BI  the global configuration object
 * @return {array} the sorted items of 'path/to/main/files.js'
 */
var prioritizeDependencies = function (BI) {
  var grouped = _.groupBy(BI.get('global-dependencies').get(), 'dependents');
  var sorted = [];

  _.each(grouped, function (dependencies, index) {
    _.chain(dependencies).groupBy(function (dependency) {
      return _.size(dependency.dependencies);
    }).toArray().value().reverse().forEach(function (dependency) {
      _.each(dependency, function (dependency) {
        sorted.push(dependency.main);
      });
    });
  });

  return sorted.reverse();
};

/**
 * Detect dependencies of the components from `bower.json`.
 *
 * @param  {object} BI the global configuration object.
 * @return {object} BI
 */
module.exports.detect = function (BI) {
  _.each(BI.get('bower.json').dependencies, gatherInfo(BI, { nestedDependencies: true }));

  BI.set('global-dependencies-sorted', prioritizeDependencies(BI));

  return BI;
};
<|endoftext|>


<commit_before>define([
    './view-mvvm',
    './view-window',
    './view-attr',
    './view-action',
    './view-children',
    './view-listen',
    './view-render',
    './view-resize',
    './view-trigger'
], function (mvvm, subwindow, attr, action, children, listen, render, resize, trigger) {

    return function (app) {
        var $ = app.core.$;
        var _ = app.core._;
        var noop = $.noop;

        /**
         * 选项
         * @typedef ViewOptions
         * @property {boolean} [autoAction=false] - 自动绑定Action事件
         *   当在模板中使用如下写法时
         *   ```html
         *   <button data-action="add">添加</button>
         *   ```
         *   如果该属性为 `true` 将自动查找该视图的 `addHandler` 方法作为该按钮点击事件的处理函数
         *
         * @property {boolean} [autoRender=true] - 自动渲染. 视图一初始化就进行渲染
         * @property {number} [_place=0] - 插入位置（0：append，1：prepend）
         * @property {string|object} [host] - 父元素，可以是选择器或jQuery对象
         * @property {boolean} [autoResize=false] - 自适应窗口变化. 该属性设为true后当窗口大小变化时会自动调用`resize`方法，因此需要重写该方法
         * @property {boolean} [autoCreateSubview=true] - 在视图渲染时，自动创建子视图，需设置 views 属性
         * @property {boolean} [activeView=null] - 设置在switchable中默认活动的视图
         * @property {boolean} [autoST=false] -自动设置触发器. 该属性为true后，会广播 `setTriggers` 消息可将该视图的工具条由defaultToolbarTpl 指定注入到其他widget，需要额外设置 `toolbar` 项指定该视图的注入到的widget名称
         * @property {string} [toolbar='toolbar'] - 触发器放置的 widget name
         * @property {string} [defaultToolbarTpl='.tpl-toolbar'] - 触发器默认模板的选择器
         * @property {object} [windowOptions=false] - 设置当视图单独位于窗口中时，窗口的选项
         * @property {object} [sharedModel=null] - 视图没有自己的视图模型，来源于该属性共享的视图模型
         * @property {array} [sharedModelProp=null] - 共享视图模型的属性集合
         *   ```
         *   [['destPropName', 'originPropName'], 'propName2']
         *   ```
         * @property {string} [langClass=null] - 视图所属的 language class 在模板中，可通过`data.lang.xxx` 来访问特定的语言文本
         * @property {boolean} [bindEmptyModel=false] - 当视图模型没赋值时 是否也进行绑定
         * @property {string} [activeView=null] - 初始活动的子视图名称
         */

        /** @lends veronica.View# */
        var base = {

            /**
             * 该视图的默认参数
             * @type {object}
             * @default
             */
            defaults: {},

            /**
             * 配置该视图的子视图 **`重写`**
             * @type {function}
             * @default
             * @example
             *   aspect: function(){
             *     this.after('initAttr', function(){
             *         this.param = { test: 'A' }
             *     });
             *     this.before // ...
             *   }
             */
            aspect: noop,

            /**
             * **`重写`** 视图的自定义初始化代码
             * @type {function}
             * @default
             */
            init: noop,

            /**
             * **`重写`** 混入其他视图方法
             * @type {function}
             * @returns {array}
             * @example
             *   mixins: function () {
             *       return [editHelper];
             *   }
             */
            mixins: noop,

            /**
             * **`重写`** 自定义销毁，通常用于释放视图使用的全局资源
             * @type {function}
             * @example
             *   _customDestory: function () {
             *     $(window).off('resize', this.resizeHanlder);
             *   }
             */
            _customDestory: noop,

            _defaults: {
                autoAction: false,

                autoResize: false,
                /**
                 * @deprecated
                 * @private
                 */
                lazyTemplate: false,
                langClass: null
            },

            /**
             * 视图初始化
             * @function
             * @inner
             * @listens View#initialize
             */
            initialize: function (options) {

                options || (options = {});

                /**
                 * 视图的配置参数
                 * @name options
                 * @memberOf View#
                 * @type {ViewOptions}
                 * @todo 这里参数默认值合并使用了深拷贝，大多数时候其实没必要，目前实际测试速度影响暂时不大
                 */
                this.options = $.extend(true, {}, this._defaults, this.defaults, options);

                /**
                 * 默认绑定视图对象到函数上下文的函数
                 * @name binds
                 * @memberOf View#
                 */
                this.binds = ['resize'];

                this._windows = {};  // 子窗口集合
                this._views = {};  // 子视图集合
                this._delayEvents = [];
                this._attributes = {};
                this.state = {};  // 视图状态

                this.baseModel = _.isFunction(this.staticModel) ? this._invoke('staticModel') : this.staticModel;
                this.viewModel = {};  // 该视图的视图模型
                this._activeViewName = null;
                this._name = options._name;

                // 将方法绑定到当前视图
                if (this.binds) {
                    this.binds.unshift(this);
                    _.bindAll.apply(_, this.binds);
                }

                // 混入AOP方法
                app.core.util.extend(this, app.core.aspect);

                // 应用mixins
                this._applyMixins();

                this.$el.addClass('ver-view');

                this._invoke('_loadPlugin');

                this._invoke('aspect');

                this._invoke('_defaultListen');

                this._invoke('_autoResize');

                this._invoke('_resetParentWnd');

                this._invoke('_initModel');

                // 初始化自定义属性
                this._invoke('initAttr');

                this._invoke('subscribe');  // 初始化广播监听

                this._invoke('_autoAction');

                this._invoke('init');

                this.trigger('init');

                // 渲染
                this.options.autoRender && this.render();
            },
            _applyMixins: function () {
                var me = this;
                var mixins = this._invoke('mixins');
                var mixin = $.extend.apply([{}].concat(mixins));
                _.each(mixin, function (value, key) {
                    if (me[key] == null) {
                        me[key] = value;
                    }
                });
            },

            _invoke: function (methodName, isWithDefaultParams) {
                var args = _.toArray(arguments);
                var sliceLen = args.length >= 2 ? 2 : 1;
                if (isWithDefaultParams == null) { isWithDefaultParams = true; }

                if (isWithDefaultParams) {
                    args = args.concat([app, _, $]);
                }

                var method = methodName;
                if (_.isString(methodName)) {
                    method = this[methodName];
                }

                return method && method.apply(this, args.slice(sliceLen));
            },
            /**
              * 显示该视图
              * @function
              */
            show: function () {
                var me = this;
                this.$el.show(false, function () {
                    if (me.options.autoResize) {
                        me.resize();
                    }
                });
            },
            /**
              * 隐藏该视图
              * @function
              */
            hide: function () {
                this.$el.hide(false);
            },

            _destroy: function () {
                // 清理在全局注册的事件处理器
                this.options.autoResize && $(window).off('resize', this.resize);

                this._invoke('_destroyWindow', false);

                // 销毁该视图的所有子视图
                this._invoke('_destroyView', false);

                // 销毁第三方组件
                this._invoke('_customDestory');

                // 清除引用
                this.viewModel = null;

                this.options.sandbox.log('destroyed');
            },
            /**
             * 销毁该视图
             */
            destroy: function () {
                this._destroy();
            }
        };

        /**
         * @classdesc 视图
         * @class veronica.View
         * @augments Backbone.View
         */
        app.view.base = base;

        mvvm(app);
        subwindow(app);
        attr(app);
        action(app);
        children(app);
        listen(app);
        render(app);
        resize(app);
        trigger(app);
    };
});
<commit_msg>fixed '_invoke' bug<commit_after>define([
    './view-mvvm',
    './view-window',
    './view-attr',
    './view-action',
    './view-children',
    './view-listen',
    './view-render',
    './view-resize',
    './view-trigger'
], function (mvvm, subwindow, attr, action, children, listen, render, resize, trigger) {

    return function (app) {
        var $ = app.core.$;
        var _ = app.core._;
        var noop = $.noop;

        /**
         * 选项
         * @typedef ViewOptions
         * @property {boolean} [autoAction=false] - 自动绑定Action事件
         *   当在模板中使用如下写法时
         *   ```html
         *   <button data-action="add">添加</button>
         *   ```
         *   如果该属性为 `true` 将自动查找该视图的 `addHandler` 方法作为该按钮点击事件的处理函数
         *
         * @property {boolean} [autoRender=true] - 自动渲染. 视图一初始化就进行渲染
         * @property {number} [_place=0] - 插入位置（0：append，1：prepend）
         * @property {string|object} [host] - 父元素，可以是选择器或jQuery对象
         * @property {boolean} [autoResize=false] - 自适应窗口变化. 该属性设为true后当窗口大小变化时会自动调用`resize`方法，因此需要重写该方法
         * @property {boolean} [autoCreateSubview=true] - 在视图渲染时，自动创建子视图，需设置 views 属性
         * @property {boolean} [activeView=null] - 设置在switchable中默认活动的视图
         * @property {boolean} [autoST=false] -自动设置触发器. 该属性为true后，会广播 `setTriggers` 消息可将该视图的工具条由defaultToolbarTpl 指定注入到其他widget，需要额外设置 `toolbar` 项指定该视图的注入到的widget名称
         * @property {string} [toolbar='toolbar'] - 触发器放置的 widget name
         * @property {string} [defaultToolbarTpl='.tpl-toolbar'] - 触发器默认模板的选择器
         * @property {object} [windowOptions=false] - 设置当视图单独位于窗口中时，窗口的选项
         * @property {object} [sharedModel=null] - 视图没有自己的视图模型，来源于该属性共享的视图模型
         * @property {array} [sharedModelProp=null] - 共享视图模型的属性集合
         *   ```
         *   [['destPropName', 'originPropName'], 'propName2']
         *   ```
         * @property {string} [langClass=null] - 视图所属的 language class 在模板中，可通过`data.lang.xxx` 来访问特定的语言文本
         * @property {boolean} [bindEmptyModel=false] - 当视图模型没赋值时 是否也进行绑定
         * @property {string} [activeView=null] - 初始活动的子视图名称
         */

        /** @lends veronica.View# */
        var base = {

            /**
             * 该视图的默认参数
             * @type {object}
             * @default
             */
            defaults: {},

            /**
             * 配置该视图的子视图 **`重写`**
             * @type {function}
             * @default
             * @example
             *   aspect: function(){
             *     this.after('initAttr', function(){
             *         this.param = { test: 'A' }
             *     });
             *     this.before // ...
             *   }
             */
            aspect: noop,

            /**
             * **`重写`** 视图的自定义初始化代码
             * @type {function}
             * @default
             */
            init: noop,

            /**
             * **`重写`** 混入其他视图方法
             * @type {function}
             * @returns {array}
             * @example
             *   mixins: function () {
             *       return [editHelper];
             *   }
             */
            mixins: noop,

            /**
             * **`重写`** 自定义销毁，通常用于释放视图使用的全局资源
             * @type {function}
             * @example
             *   _customDestory: function () {
             *     $(window).off('resize', this.resizeHanlder);
             *   }
             */
            _customDestory: noop,

            _defaults: {
                autoAction: false,

                autoResize: false,
                /**
                 * @deprecated
                 * @private
                 */
                lazyTemplate: false,
                langClass: null
            },

            /**
             * 视图初始化
             * @function
             * @inner
             * @listens View#initialize
             */
            initialize: function (options) {

                options || (options = {});

                /**
                 * 视图的配置参数
                 * @name options
                 * @memberOf View#
                 * @type {ViewOptions}
                 * @todo 这里参数默认值合并使用了深拷贝，大多数时候其实没必要，目前实际测试速度影响暂时不大
                 */
                this.options = $.extend(true, {}, this._defaults, this.defaults, options);

                /**
                 * 默认绑定视图对象到函数上下文的函数
                 * @name binds
                 * @memberOf View#
                 */
                this.binds = ['resize'];

                this._windows = {};  // 子窗口集合
                this._views = {};  // 子视图集合
                this._delayEvents = [];
                this._attributes = {};
                this.state = {};  // 视图状态

                this.baseModel = _.isFunction(this.staticModel) ? this._invoke('staticModel') : this.staticModel;
                this.viewModel = {};  // 该视图的视图模型
                this._activeViewName = null;
                this._name = options._name;

                // 将方法绑定到当前视图
                if (this.binds) {
                    this.binds.unshift(this);
                    _.bindAll.apply(_, this.binds);
                }

                // 混入AOP方法
                app.core.util.extend(this, app.core.aspect);

                // 应用mixins
                this._applyMixins();

                this.$el.addClass('ver-view');

                this._invoke('_loadPlugin');

                this._invoke('aspect');

                this._invoke('_defaultListen');

                this._invoke('_autoResize');

                this._invoke('_resetParentWnd');

                this._invoke('_initModel');

                // 初始化自定义属性
                this._invoke('initAttr');

                this._invoke('subscribe');  // 初始化广播监听

                this._invoke('_autoAction');

                this._invoke('init');

                this.trigger('init');

                // 渲染
                this.options.autoRender && this.render();
            },
            _applyMixins: function () {
                var me = this;
                var mixins = this._invoke('mixins');
                var mixin = $.extend.apply([{}].concat(mixins));
                _.each(mixin, function (value, key) {
                    if (me[key] == null) {
                        me[key] = value;
                    }
                });
            },

            _invoke: function (methodName, isWithDefaultParams) {
                var args = _.toArray(arguments);
                var sliceLen = args.length >= 2 ? 2 : 1;
                if (isWithDefaultParams == null) { isWithDefaultParams = true; }

                if (isWithDefaultParams) {
                    args = args.concat([app, _, $]);
                }

                var method = methodName;
                if (_.isString(methodName)) {
                    method = this[methodName];
                }

                return _.isFunction(method) ? method.apply(this, args.slice(sliceLen)) : method;
            },
            /**
              * 显示该视图
              * @function
              */
            show: function () {
                var me = this;
                this.$el.show(false, function () {
                    if (me.options.autoResize) {
                        me.resize();
                    }
                });
            },
            /**
              * 隐藏该视图
              * @function
              */
            hide: function () {
                this.$el.hide(false);
            },

            _destroy: function () {
                // 清理在全局注册的事件处理器
                this.options.autoResize && $(window).off('resize', this.resize);

                this._invoke('_destroyWindow', false);

                // 销毁该视图的所有子视图
                this._invoke('_destroyView', false);

                // 销毁第三方组件
                this._invoke('_customDestory');

                // 清除引用
                this.viewModel = null;

                this.options.sandbox.log('destroyed');
            },
            /**
             * 销毁该视图
             */
            destroy: function () {
                this._destroy();
            }
        };

        /**
         * @classdesc 视图
         * @class veronica.View
         * @augments Backbone.View
         */
        app.view.base = base;

        mvvm(app);
        subwindow(app);
        attr(app);
        action(app);
        children(app);
        listen(app);
        render(app);
        resize(app);
        trigger(app);
    };
});
<|endoftext|>


<commit_before>const config = require('./config.js');
const fs = require('fs');
const bin = require('./binary.js');
const crc = require('./crc.js');
const ham = require('./hamming.js');
const flg = require('./flags.js');

function createPacket(packet) {
	console.log('Rosquete');
	console.log(packet);

	console.log('\nConteo de caracteres:')
	packet = bin.addCharCont(packet);
	console.log(packet);

	switch (config.MODE) {
	 	case 'crc':
	 		console.log('\nCRC-16:')
	 		packet = crc.crc_16(packet);
	 		console.log(packet);
	 		break;

	 	case 'hamming':
	 		console.log('\nHamming:')
	 		packet = ham.segHamming(packet);
	 		console.log(packet);
	 		break

	 	default:
	 		break;
	}

	console.log('\nRelleno:')
	packet = flg.relleno(packet);
	console.log(packet);

	console.log('\nBanderas:')
	packet = flg.banderiador(packet);
	console.log(packet);
	return packet;
}

function disasPacket(packet) {

	console.log('\nBanderas:');
	packet = flg.apatrida(packet);
	console.log(packet);

	console.log('\nRelleno:');
	packet = flg.desRelleno(packet);
	console.log(packet);

	switch (config.MODE) {
		case 'crc':
	 		console.log('\nCRC-16:');
	 		console.log(crc.crc_16_Ver(packet) ? 'Nene' : 'Pupu');
	 		packet = crc.unCrc(packet);
	 		console.log(packet);
	 		break;

	 	case 'hamming':
	 		console.log('\nHamming:');

	 		let code = ham.correctPacket(packet);
	 		for (let s of code) {
	 			console.log(s);
	 		}

	 		packet = code.map(h => {
	 			if (h.err != -1) console.log('Ay papa: ', h.err);
	 			return h.bits;
	 		}).join('');

	 		console.log(packet);

	 		packet = ham.remPacketParityBits(packet);
	 		console.log(packet);

	 		break

	 	default:
	 		break;
	}

	console.log('\nConteo:');
	console.log(bin.bytesContCheck(packet) ? 'Nene' : 'Pupu');
	packet = bin.remCharCont(packet);

	console.log(packet);

	return packet;
}

function processChunk(chunk,text = true) {

	let tramas = [];

	if(text) tramas.push("01111110000000000001111110");

	for (let b of bin.bytes2Bits(chunk)) {
		let trama = createPacket(b);

		tramas.push(trama);
	}

	if(text) tramas.push("01111110000000000001111110");
};

exports.processChunk = processChunk;

exports.readFile = (path) => {
	const stream = fs.createReadStream(path);
	stream.on('data' , processChunk);
	stream.on('error', (err) => {
		console.log(err);
	});
}

// readFile(config.MSG_FILE);
<commit_msg>Solve Text Bug<commit_after>const config = require('./config.js');
const fs = require('fs');
const bin = require('./binary.js');
const crc = require('./crc.js');
const ham = require('./hamming.js');
const flg = require('./flags.js');

function createPacket(packet) {
	console.log('Rosquete');
	console.log(packet);

	console.log('\nConteo de caracteres:')
	packet = bin.addCharCont(packet);
	console.log(packet);

	switch (config.MODE) {
	 	case 'crc':
	 		console.log('\nCRC-16:')
	 		packet = crc.crc_16(packet);
	 		console.log(packet);
	 		break;

	 	case 'hamming':
	 		console.log('\nHamming:')
	 		packet = ham.segHamming(packet);
	 		console.log(packet);
	 		break

	 	default:
	 		break;
	}

	console.log('\nRelleno:')
	packet = flg.relleno(packet);
	console.log(packet);

	console.log('\nBanderas:')
	packet = flg.banderiador(packet);
	console.log(packet);
	return packet;
}

function disasPacket(packet) {

	console.log('\nBanderas:');
	packet = flg.apatrida(packet);
	console.log(packet);

	console.log('\nRelleno:');
	packet = flg.desRelleno(packet);
	console.log(packet);

	switch (config.MODE) {
		case 'crc':
	 		console.log('\nCRC-16:');
	 		console.log(crc.crc_16_Ver(packet) ? 'Nene' : 'Pupu');
	 		packet = crc.unCrc(packet);
	 		console.log(packet);
	 		break;

	 	case 'hamming':
	 		console.log('\nHamming:');

	 		let code = ham.correctPacket(packet);
	 		for (let s of code) {
	 			console.log(s);
	 		}

	 		packet = code.map(h => {
	 			if (h.err != -1) console.log('Ay papa: ', h.err);
	 			return h.bits;
	 		}).join('');

	 		console.log(packet);

	 		packet = ham.remPacketParityBits(packet);
	 		console.log(packet);

	 		break

	 	default:
	 		break;
	}

	console.log('\nConteo:');
	console.log(bin.bytesContCheck(packet) ? 'Nene' : 'Pupu');
	packet = bin.remCharCont(packet);

	console.log(packet);

	return packet;
}

function processChunk(chunk,text = true) {

	let tramas = [];

	if(!text) tramas.push("01111110000000000001111110");

	for (let b of bin.bytes2Bits(chunk)) {
		let trama = createPacket(b);

		tramas.push(trama);
	}

	if(!text) tramas.push("01111110000000000001111110");
};

exports.processChunk = processChunk;

exports.readFile = (path) => {
	const stream = fs.createReadStream(path);
	stream.on('data' , processChunk);
	stream.on('error', (err) => {
		console.log(err);
	});
}

// readFile(config.MSG_FILE);
<|endoftext|>


<commit_before>'use strict';

const redis = require('redis');
const Lib = require('../src');
const error = require('../src/error');

describe('Lock', () => {
	this.lockName = 'testing-lock-name';
	this.lock = new Lib();

	afterEach((done) => {
		this.lock
		.release(this.lockName)
		.then(() => {
			done();
		})
		.catch(err => {
			done();
		});
	});

	it('should throw on wrong key', () => {
		expect(() => {
			this.lock.lock();
		}).toThrow(new TypeError('You should provide "key" as a string'));
	});

	it('should clean timeout after loop launches and lock obtain failed', (done) => {
		const client = new redis.createClient();
		var retries  = 0;

		spyOn(client, 'set').and.callFake(function(key, value, nx, px, ttl, cb) {
			retries++;

			if (retries > 3) {
				return cb(new Error(`Some Redis Error`));
			} else {
				return null;
			}
		});

		const lock = new Lib({
			client: client
		});

		lock.lock(this.lockName, (err, result) => {
			expect(err).not.toEqual(null);
			expect(err).toEqual(new error.RedisError(`Error: Some Redis Error`));
			done();
		});
	});

	describe('Promises', () => {
		it('should lock with default params', (done) => {
			this.lock.lock(this.lockName).then(data => {
				expect(data.elapsed).not.toEqual(undefined);
				expect(data.attempts).not.toEqual(undefined);
				done();
			});
		});

		it('should lock when we providing custom params timeout/ttl', (done) => {
			this.lock
			.lock(this.lockName, {ttl: 0.1, timeout: 1})
			.then(data => {
				expect(data.elapsed).not.toEqual(undefined);
				expect(data.attempts).not.toEqual(undefined);

				return new Promise((resolve, reject) => {
					setTimeout(() => {
						return resolve(this.lock.release(this.lockName));
					}, 200);
				});
			})
			.catch(err => {
				expect(err).toEqual(new error.ReleaseError('Lock release error, there is no such lock'));
				done();
			});
		});

		it('should throw on lock obtain failure', (done) => {
			this.lock
			.lock(this.lockName)
			.then(() => {
				this.lock
				.lock(this.lockName, {timeout: 1})
				.catch(err => {
					expect(err).toEqual(new error.AcquireError('Error while obtaining lock'));
					done();
				});
			});
		});

		it('should return Redis error', (done) => {
			const client = new redis.createClient();

			spyOn(client, 'set').and.callFake(function(key, value, nx, px, ttl, cb) {
				return cb(new Error(`Some Redis Error`));
			});

			const lock = new Lib({
				client: client
			});

			lock
			.lock(this.lockName)
			.catch(err => {
				expect(err).not.toEqual(null);
				expect(err).toEqual(new error.RedisError(`Error: Some Redis Error`));
				done();
			});
		});

	});

	describe('Callbacks', () => {
		it('should lock with default params', (done) => {
			this.lock.lock(this.lockName, (err, data) => {
				expect(err).toEqual(null);
				expect(data.elapsed).not.toEqual(undefined);
				expect(data.attempts).not.toEqual(undefined);

				done();
			});
		});

		it('should lock when we provide custom params timeout/ttl', (done) => {
			this.lock.lock(this.lockName, {ttl: 0.1, timeout: 10}, (err, data) => {
				expect(data.elapsed).not.toEqual(undefined);
				expect(data.attempts).not.toEqual(undefined);

				setTimeout(() => {
					this.lock.release(this.lockName, (err) => {
						expect(err).toEqual(new error.ReleaseError('Lock release error, there is no such lock'));
						done();
					});
				}, 150);
			});
		});

		it('should return error on lock obtain failure', (done) => {
			this.lock.lock(this.lockName, (err, data) => {
				this.lock.lock(this.lockName, {timeout: 1}, (err) => {
					expect(err).toEqual(new error.AcquireError('Error while obtaining lock'));
					done();
				});
			});
		});

		it('should return Redis error', (done) => {
			const client = new redis.createClient();

			spyOn(client, 'set').and.callFake(function(key, value, nx, px, ttl, cb) {
				return cb(new Error(`Some Redis Error`));
			});

			const lock = new Lib({
				client: client
			});

			lock.lock(this.lockName, (err, result) => {
				expect(err).not.toEqual(null);
				expect(err).toEqual(new error.RedisError(`Error: Some Redis Error`));
				done();
			});
		});

	});
});
<commit_msg>Added more timeout to callback way ttl spec<commit_after>'use strict';

const redis = require('redis');
const Lib = require('../src');
const error = require('../src/error');

describe('Lock', () => {
	this.lockName = 'testing-lock-name';
	this.lock = new Lib();

	afterEach((done) => {
		this.lock
		.release(this.lockName)
		.then(() => {
			done();
		})
		.catch(err => {
			done();
		});
	});

	it('should throw on wrong key', () => {
		expect(() => {
			this.lock.lock();
		}).toThrow(new TypeError('You should provide "key" as a string'));
	});

	it('should clean timeout after loop launches and lock obtain failed', (done) => {
		const client = new redis.createClient();
		var retries  = 0;

		spyOn(client, 'set').and.callFake(function(key, value, nx, px, ttl, cb) {
			retries++;

			if (retries > 3) {
				return cb(new Error(`Some Redis Error`));
			} else {
				return null;
			}
		});

		const lock = new Lib({
			client: client
		});

		lock.lock(this.lockName, (err, result) => {
			expect(err).not.toEqual(null);
			expect(err).toEqual(new error.RedisError(`Error: Some Redis Error`));
			done();
		});
	});

	describe('Promises', () => {
		it('should lock with default params', (done) => {
			this.lock.lock(this.lockName).then(data => {
				expect(data.elapsed).not.toEqual(undefined);
				expect(data.attempts).not.toEqual(undefined);
				done();
			});
		});

		it('should lock when we providing custom params timeout/ttl', (done) => {
			this.lock
			.lock(this.lockName, {ttl: 0.1, timeout: 1})
			.then(data => {
				expect(data.elapsed).not.toEqual(undefined);
				expect(data.attempts).not.toEqual(undefined);

				return new Promise((resolve, reject) => {
					setTimeout(() => {
						return resolve(this.lock.release(this.lockName));
					}, 200);
				});
			})
			.catch(err => {
				expect(err).toEqual(new error.ReleaseError('Lock release error, there is no such lock'));
				done();
			});
		});

		it('should throw on lock obtain failure', (done) => {
			this.lock
			.lock(this.lockName)
			.then(() => {
				this.lock
				.lock(this.lockName, {timeout: 1})
				.catch(err => {
					expect(err).toEqual(new error.AcquireError('Error while obtaining lock'));
					done();
				});
			});
		});

		it('should return Redis error', (done) => {
			const client = new redis.createClient();

			spyOn(client, 'set').and.callFake(function(key, value, nx, px, ttl, cb) {
				return cb(new Error(`Some Redis Error`));
			});

			const lock = new Lib({
				client: client
			});

			lock
			.lock(this.lockName)
			.catch(err => {
				expect(err).not.toEqual(null);
				expect(err).toEqual(new error.RedisError(`Error: Some Redis Error`));
				done();
			});
		});

	});

	describe('Callbacks', () => {
		it('should lock with default params', (done) => {
			this.lock.lock(this.lockName, (err, data) => {
				expect(err).toEqual(null);
				expect(data.elapsed).not.toEqual(undefined);
				expect(data.attempts).not.toEqual(undefined);

				done();
			});
		});

		it('should lock when we provide custom params timeout/ttl', (done) => {
			this.lock.lock(this.lockName, {ttl: 0.1, timeout: 10}, (err, data) => {
				expect(data.elapsed).not.toEqual(undefined);
				expect(data.attempts).not.toEqual(undefined);

				setTimeout(() => {
					this.lock.release(this.lockName, (err) => {
						expect(err).toEqual(new error.ReleaseError('Lock release error, there is no such lock'));
						done();
					});
				}, 450);
			});
		});

		it('should return error on lock obtain failure', (done) => {
			this.lock.lock(this.lockName, (err, data) => {
				this.lock.lock(this.lockName, {timeout: 1}, (err) => {
					expect(err).toEqual(new error.AcquireError('Error while obtaining lock'));
					done();
				});
			});
		});

		it('should return Redis error', (done) => {
			const client = new redis.createClient();

			spyOn(client, 'set').and.callFake(function(key, value, nx, px, ttl, cb) {
				return cb(new Error(`Some Redis Error`));
			});

			const lock = new Lib({
				client: client
			});

			lock.lock(this.lockName, (err, result) => {
				expect(err).not.toEqual(null);
				expect(err).toEqual(new error.RedisError(`Error: Some Redis Error`));
				done();
			});
		});

	});
});
<|endoftext|>


<commit_before>$(function() {
	$('.dropdown-toggle').dropdown();
	$('.dropdown input, .dropdown label').click(function(e) {
		e.stopPropagation();
	});

	var gameDisplay = {
		isInitialized: false,
		init: function() {
			this.isInitialized = true;
			this.cacheDOM();
		},
		cacheDOM: function() {
			this.$modal = $("#gameModal");
			this.$player1Field = $("#player1");
			this.$player2Field = $("#player2");
		},
		setGame: function(player1, player2, replayFilename) {
			if(this.isInitialized == false) this.init();

			this.player1 = player1;
			this.player2 = player2;
			this.replayFilename = replayFilename;
			this.render();
		},
		render: function() {
			this.$modal.modal('show');
			this.$player1Field.html(this.player1.firstName + " " + this.player1.lastName);
			this.$player2Field.html(this.player2.firstName + " " + this.player2.lastName);
			begin(getGameFile(this.replayFilename));
		},
		hide: function() {
			this$modal.modal('hide');
		}
	}

	function GameDropdown(user, $parentField) {
		this.setGames = function(games) {
			this.games = games;
			this.render();
			this.hide();
		};
		this.render = function() {
			this.$parentField.find(".gameRow").remove();
			for(var a = 0; a < this.games.length; a++) {
				var opponent = this.games[a].users[0].userID == this.user.userID ? this.games[a].users[1] : this.games[a].users[0];
				var gameResult = opponent.rank === "0" ? "Lost" : "Won";

				this.$parentField.append("
	vs "+opponent.firstName+" "+opponent.lastName+"	"+opponent.schoolName+"	"+gameResult+"
");
			}
		};
		this.toggle = function() {
			if(this.isShown == true) this.hide();
			else this.show();
		};
		this.hide = function() {
			this.isShown = false;
			this.$parentField.find(".gameRow").css("display", "none");
		};
		this.show = function() {
			this.isShown = true;
			this.$parentField.find(".gameRow").css("display", "table-row");
		};
		this.displayGame = function(event) {
			var gameID = $(event.toElement).attr("gameID");
			var game = null;
			for(var a = 0; a < this.games.length; a++) {
				if(this.games[a].gameID == gameID) {
					game = this.games[a];
					break;
				}
			}
			gameDisplay.setGame(game.users[0], game.users[1], game.replayFilename);
		};

		this.user = user;
		this.$parentField = $parentField;
		console.log("bind")
		$(document).on("click", ".gameLink"+this.user.userID, this.displayGame.bind(this));
	}

	var table = {
		init: function(submissions) {
			this.cacheDOM();
			this.bindEvents();
			this.setSubmissions(submissions);
		},
		cacheDOM: function() {
			this.$table = $("#leaderTable")
		},
		bindEvents: function() {
			$(document).on("click", ".matchDrop", this.toggleDropdown.bind(this));
		},
		setSubmissions: function(submissions) {
			this.submissions = submissions;

			this.render();

			this.dropdowns = Array();
			for(var a = 0; a < this.submissions.length; a++) this.dropdowns.push(new GameDropdown(this.submissions[a].user, $("#user"+this.submissions[a].user.userID)));
		},
		render: function() {
			this.$table.empty();
			for(var a = 0; a < this.submissions.length; a++) {
				var user = this.submissions[a].user;
				var score = this.submissions[a].score;
				this.$table.append("

"+(a+1)+"	"+user.firstName+" "+user.lastName+"	"+user.schoolName+"	"+score+"

");
			}
		},
		toggleDropdown: function(event) {
			var user = this.getUserWithID($(event.toElement).attr("userID"));
			for(var a = 0; a < this.submissions.length; a++) {
				if(this.submissions[a].user.userID == user.userID) {
					console.log(user.userID)
					if(this.dropdowns[a].games == null) this.dropdowns[a].setGames(getLatestGamesForUser(user.userID));
					this.dropdowns[a].toggle();
					break;
				}
			}
		},
		getUserWithID: function(userID) {
			for(var a = 0; a < this.submissions.length; a++) if(this.submissions[a].user.userID == userID) return this.submissions[a].user;
			return getUser(userID);
		}
	};

	var problemDisplay = {
		init: function(problem) {
			this.problem = problem;
			this.cacheDOM();
			this.render();
		},
		cacheDOM: function() {
			this.$header = $("#jHeader");
			this.$paragraph = $("#jParagraph");
			this.$rulesPanel = $("#rulesPanelBody");

			this.table = table;
			this.table.init(this.problem.submissions);
		},
		setProblem: function(problem) {
			this.problem = problem;
			this.table.setSubmissions(problem.submissions);
			this.render();
		},
		render: function() {
			this.$header.html(this.problem.problemFullName);
			this.$paragraph.html(this.problem.problemDescription);

			var result = $.ajax({
				url: "problems/descriptions/"+this.problem.problemName+".html",
				async: true,
				method: "GET",
				context: this,
				success: function(result) {
					this.$rulesPanel.html(result);
				}
		    });
		},
	};

	var problemPanner = {
		init: function(startingIndex) {
			this.problemIndex = startingIndex;
			this.problemSize = getProblemsSize();

			this.cacheDOM();
			this.bindEvents();
		},
		cacheDOM: function() {
			this.$backButton = $("#backButton");
			this.$forwardButton = $("#nextButton");
			this.$archivedTag = $("archivedTag");

			this.problemDisplay = problemDisplay;
			this.problemDisplay.init(getProblemWithIndex(this.problemIndex));

			if(this.problemIndex == 0) {
				this.$forwardButton.css("visibility", "hidden");
				this.$archivedTag.css("display", "none");
			}
			if(this.problemIndex == this.problemSize-1) {
				this.$backButton.css("visibility", "visible");
			}
		},
		bindEvents: function() {
			this.$backButton.click(this, this.moveBack.bind(this));
			this.$forwardButton.click(this, this.moveForward.bind(this));
		},
		render: function() {
			this.problemDisplay.setProblem(getProblemWithIndex(this.problemIndex));
		},
		moveBack: function() {
			this.problemIndex++;
			if(this.problemIndex == this.problemSize-1) {
				this.$backButton.css("visibility", "hidden");
			}
			if(this.problemIndex == 1) {
				this.$forwardButton.css("visibility", "visible");
				this.$archivedTag.css("display", "block");
			}

			this.render();
		},
		moveForward: function() {
			this.problemIndex--;
			if(this.problemIndex == 0) {
				this.$forwardButton.css("visibility", "hidden");
				this.$archivedTag.css("display", "none");
			}
			if(this.problemIndex == this.problemSize-2) {
				this.$backButton.css("visibility", "visible");
			}

			this.render();
		}
	};

	// Get problem index from GET parameter
	var index = parseInt(getGET("problemIndex"));
	if(isNaN(index) == true || index == null || index === "" || index === " ") {
		index = parseInt(getGET("problemID"));
		if(isNaN(index) == true || index == null || index === "" || index === " ") {
			index = 0;
		} else {
			index = problemIDToIndex(index);
		}
	}
	problemPanner.init(index);

	if(getGET("didVerify") != null) verifySuccess()
	if(getGET("didNotVerify") != null) verifyError()
	if(getGET("didRecover") != null) recoverPasswordSuccess()
	if(getGET("didNotRecover") != null) recoverPasswordError()

	renderMathInElement(document.getElementById("rulesPanelBody"));
});

function verifySuccess() {
	$("#messageBox").empty()
	$("#messageBox").append($("
<button type='button' class='close' data-dismiss='alert' aria-label='Close'>×</button>Email Verification Success.  Your email has been verified. You may now log in.
"))
}

function verifyError() {
	$("#messageBox").empty()
	$("#messageBox").append($("
<button type='button' class='close' data-dismiss='alert' aria-label='Close'>×</button>Email Verification Failed.  There was a problem verifying your email.
"))
}

function recoverPasswordSuccess() {
	$("#messageBox").empty()
	$("#messageBox").append($("
<button type='button' class='close' data-dismiss='alert' aria-label='Close'>×</button>Password Changed.  You successfully changed your password!
"))
}

function recoverPasswordError() {
	$("#messageBox").empty()
	$("#messageBox").append($("
<button type='button' class='close' data-dismiss='alert' aria-label='Close'>×</button>Password Change Failed.  There was a problem changing your password. If this issue is persistent, email contact@nycsl.io.
"))
}<commit_msg>typo fix<commit_after>$(function() {
	$('.dropdown-toggle').dropdown();
	$('.dropdown input, .dropdown label').click(function(e) {
		e.stopPropagation();
	});

	var gameDisplay = {
		isInitialized: false,
		init: function() {
			this.isInitialized = true;
			this.cacheDOM();
		},
		cacheDOM: function() {
			this.$modal = $("#gameModal");
			this.$player1Field = $("#player1");
			this.$player2Field = $("#player2");
		},
		setGame: function(player1, player2, replayFilename) {
			if(this.isInitialized == false) this.init();

			this.player1 = player1;
			this.player2 = player2;
			this.replayFilename = replayFilename;
			this.render();
		},
		render: function() {
			this.$modal.modal('show');
			this.$player1Field.html(this.player1.firstName + " " + this.player1.lastName);
			this.$player2Field.html(this.player2.firstName + " " + this.player2.lastName);
			begin(getGameFile(this.replayFilename));
		},
		hide: function() {
			this.$modal.modal('hide');
		}
	}

	function GameDropdown(user, $parentField) {
		this.setGames = function(games) {
			this.games = games;
			this.render();
			this.hide();
		};
		this.render = function() {
			this.$parentField.find(".gameRow").remove();
			for(var a = 0; a < this.games.length; a++) {
				var opponent = this.games[a].users[0].userID == this.user.userID ? this.games[a].users[1] : this.games[a].users[0];
				var gameResult = opponent.rank === "0" ? "Lost" : "Won";

				this.$parentField.append("
	vs "+opponent.firstName+" "+opponent.lastName+"	"+opponent.schoolName+"	"+gameResult+"
");
			}
		};
		this.toggle = function() {
			if(this.isShown == true) this.hide();
			else this.show();
		};
		this.hide = function() {
			this.isShown = false;
			this.$parentField.find(".gameRow").css("display", "none");
		};
		this.show = function() {
			this.isShown = true;
			this.$parentField.find(".gameRow").css("display", "table-row");
		};
		this.displayGame = function(event) {
			var gameID = $(event.toElement).attr("gameID");
			var game = null;
			for(var a = 0; a < this.games.length; a++) {
				if (this.games[a].gameID == gameID) {
					game = this.games[a];
					break;
				}
			}
			gameDisplay.setGame(game.users[0], game.users[1], game.replayFilename);
		};

		this.user = user;
		this.$parentField = $parentField;
		console.log("bind")
		$(document).on("click", ".gameLink"+this.user.userID, this.displayGame.bind(this));
	}

	var table = {
		init: function(submissions) {
			this.cacheDOM();
			this.bindEvents();
			this.setSubmissions(submissions);
		},
		cacheDOM: function() {
			this.$table = $("#leaderTable")
		},
		bindEvents: function() {
			$(document).on("click", ".matchDrop", this.toggleDropdown.bind(this));
		},
		setSubmissions: function(submissions) {
			this.submissions = submissions;

			this.render();

			this.dropdowns = Array();
			for(var a = 0; a < this.submissions.length; a++) this.dropdowns.push(new GameDropdown(this.submissions[a].user, $("#user"+this.submissions[a].user.userID)));
		},
		render: function() {
			this.$table.empty();
			for(var a = 0; a < this.submissions.length; a++) {
				var user = this.submissions[a].user;
				var score = this.submissions[a].score;
				this.$table.append("

"+(a+1)+"	"+user.firstName+" "+user.lastName+"	"+user.schoolName+"	"+score+"

");
			}
		},
		toggleDropdown: function(event) {
			var user = this.getUserWithID($(event.toElement).attr("userID"));
			for(var a = 0; a < this.submissions.length; a++) {
				if(this.submissions[a].user.userID == user.userID) {
					console.log(user.userID)
					if(this.dropdowns[a].games == null) this.dropdowns[a].setGames(getLatestGamesForUser(user.userID));
					this.dropdowns[a].toggle();
					break;
				}
			}
		},
		getUserWithID: function(userID) {
			for(var a = 0; a < this.submissions.length; a++) if(this.submissions[a].user.userID == userID) return this.submissions[a].user;
			return getUser(userID);
		}
	};

	var problemDisplay = {
		init: function(problem) {
			this.problem = problem;
			this.cacheDOM();
			this.render();
		},
		cacheDOM: function() {
			this.$header = $("#jHeader");
			this.$paragraph = $("#jParagraph");
			this.$rulesPanel = $("#rulesPanelBody");

			this.table = table;
			this.table.init(this.problem.submissions);
		},
		setProblem: function(problem) {
			this.problem = problem;
			this.table.setSubmissions(problem.submissions);
			this.render();
		},
		render: function() {
			this.$header.html(this.problem.problemFullName);
			this.$paragraph.html(this.problem.problemDescription);

			var result = $.ajax({
				url: "problems/descriptions/"+this.problem.problemName+".html",
				async: true,
				method: "GET",
				context: this,
				success: function(result) {
					this.$rulesPanel.html(result);
				}
		    });
		},
	};

	var problemPanner = {
		init: function(startingIndex) {
			this.problemIndex = startingIndex;
			this.problemSize = getProblemsSize();

			this.cacheDOM();
			this.bindEvents();
		},
		cacheDOM: function() {
			this.$backButton = $("#backButton");
			this.$forwardButton = $("#nextButton");
			this.$archivedTag = $("archivedTag");

			this.problemDisplay = problemDisplay;
			this.problemDisplay.init(getProblemWithIndex(this.problemIndex));

			if(this.problemIndex == 0) {
				this.$forwardButton.css("visibility", "hidden");
				this.$archivedTag.css("display", "none");
			}
			if(this.problemIndex == this.problemSize-1) {
				this.$backButton.css("visibility", "visible");
			}
		},
		bindEvents: function() {
			this.$backButton.click(this, this.moveBack.bind(this));
			this.$forwardButton.click(this, this.moveForward.bind(this));
		},
		render: function() {
			this.problemDisplay.setProblem(getProblemWithIndex(this.problemIndex));
		},
		moveBack: function() {
			this.problemIndex++;
			if(this.problemIndex == this.problemSize-1) {
				this.$backButton.css("visibility", "hidden");
			}
			if(this.problemIndex == 1) {
				this.$forwardButton.css("visibility", "visible");
				this.$archivedTag.css("display", "block");
			}

			this.render();
		},
		moveForward: function() {
			this.problemIndex--;
			if(this.problemIndex == 0) {
				this.$forwardButton.css("visibility", "hidden");
				this.$archivedTag.css("display", "none");
			}
			if(this.problemIndex == this.problemSize-2) {
				this.$backButton.css("visibility", "visible");
			}

			this.render();
		}
	};

	// Get problem index from GET parameter
	var index = parseInt(getGET("problemIndex"));
	if(isNaN(index) == true || index == null || index === "" || index === " ") {
		index = parseInt(getGET("problemID"));
		if(isNaN(index) == true || index == null || index === "" || index === " ") {
			index = 0;
		} else {
			index = problemIDToIndex(index);
		}
	}
	problemPanner.init(index);

	if(getGET("didVerify") != null) verifySuccess()
	if(getGET("didNotVerify") != null) verifyError()
	if(getGET("didRecover") != null) recoverPasswordSuccess()
	if(getGET("didNotRecover") != null) recoverPasswordError()

	renderMathInElement(document.getElementById("rulesPanelBody"));
});

function verifySuccess() {
	$("#messageBox").empty()
	$("#messageBox").append($("
<button type='button' class='close' data-dismiss='alert' aria-label='Close'>×</button>Email Verification Success.  Your email has been verified. You may now log in.
"))
}

function verifyError() {
	$("#messageBox").empty()
	$("#messageBox").append($("
<button type='button' class='close' data-dismiss='alert' aria-label='Close'>×</button>Email Verification Failed.  There was a problem verifying your email.
"))
}

function recoverPasswordSuccess() {
	$("#messageBox").empty()
	$("#messageBox").append($("
<button type='button' class='close' data-dismiss='alert' aria-label='Close'>×</button>Password Changed.  You successfully changed your password!
"))
}

function recoverPasswordError() {
	$("#messageBox").empty()
	$("#messageBox").append($("
<button type='button' class='close' data-dismiss='alert' aria-label='Close'>×</button>Password Change Failed.  There was a problem changing your password. If this issue is persistent, email contact@nycsl.io.
"))
}<|endoftext|>