<commit_before>/*jslint node: true */
"use strict";

var crypto = require('./crypto');
var models = require('./models');
var mongoose = require('mongoose');
var Promise = require('bluebird');
var restify = require('restify');
var _ = require('lodash');

var roleIsSufficient = function (role, requiredRole) {
  if (requiredRole === "admin") {
    return role === "admin";
  }
  return _.findIndex(["admin", "user"], role) !== -1;
};

module.exports.require_auth = function (requiredRole) {
  return function (req, res, next) {
    if (_.isEmpty(req.headers["x-authentication"])) {
      return next(new restify.ForbiddenError('Authorization required'));
    }
    var tokenString = req.headers["x-authentication"].split(" ")[1];
    models.Token.findOne({token: tokenString})
      .populate(['user'])
      .then(function (token) {
        if (token === null) {
          return next(new restify.ForbiddenError('Permission denied'));
        }
        if (!roleIsSufficient(token.user.role, requiredRole)) {
          return next(new restify.ForbiddenError('Permission denied'));
        }
        return next();
      })
      .catch(function (err) {
        req.log.error(err);
        next(err);
      });
  };
};

module.exports.get_player = function (req, res, next) {
  var response = {code: "success"};
  models.Player.findOne({name: req.params.name.toLowerCase()})
    .populate('series')
    .then(function (player) {
      if (player === null) {
        throw new restify.NotFoundError('Player not found');
      }
      response.player = player.toObject();
      return player.getStats({days: req.params.stats_days});
    })
    .then(function (stats) {
      response.player.stats = stats;
      res.send(response);
      return next();
    })
    .catch(function (err) {
      req.log.error(err);
      next(err);
    });
};

module.exports.create_player = function (req, res, next) {
  var player = new models.Player({displayname: req.params.name, name: req.params.name.toLowerCase()});
  player.save()
    .catch(models.MongoError, function (err) {
      return models.Player.findOne({name: req.params.name.toLowerCase()});
    })
    .then(function (player) {
      req.log.info("Added player", player.name);
      if (!_.isEmpty(req.params.series)) {
        // Maintain two-way link between Player and Series
        req.log.debug("Adding series to player", player.name);
        return models.Series.findOne({name: req.params.series})
          .then(function (series) {
            if (series === null) {
              throw new restify.NotFoundError('Series not found');
            }
            if (_.includes(_.map(series.players, function (v) { return String(v); }), player.id)) {
              return Promise.resolve();
            }
            req.log.debug("Adding player", player.name, "to series", series.name);
            series.players.push(player.id);
            return series.save()
              .catch(function (err) {
                req.log.error(err);
                return next(err);
              });
          })
          .then(function (series) {
            if (series && !player.series.some(function (s) { return s.equals(series.id); })) {
              player.series.push(series.id);
              return player.save();
            } else {
              return Promise.resolve();

            }
          })
          .then(function () {
            // Need to query the model back to get .series populated
            return models.Player.findOne({_id: player.id}).populate('series');
          })
          .then(function (player) {
            res.send({code: "success", player: player.toObject()});
            return next();
          });
      } else {
        res.send({code: "success", player: player.toObject()});
        return next();
      }
    })
    .catch(models.ValidationError, function (err) {
      req.log.error("Validation failed", err.errors);
      next(err);
    })
    .catch(function (err) {
      req.log.error(err);
      next(err);
    });
};

module.exports.create_player_token = function (req, res, next) {
  var player;
  if (_.isEmpty(req.params.password)) {
    throw new restify.BadRequestError('Missing password');
  }
  models.Player.findOne({name: req.params.name.toLowerCase()})
    .then(function (result) {
      if (result === null) {
        throw new restify.NotFoundError('Player not found');
      }
      player = result;
      return crypto.validateUser(player, req.params.password);
    })
    .then(function () {
      var token = new models.Token({user: player.id});
      return token.save();
    })
    .then(function (token) {
      res.send({code: "success", user: player.displayname, token: token.token});
      return next();
    })
    .catch(function (err) {
      req.log.error(err);
      next(err);
    });
};

module.exports.delete_player = function (req, res, next) {
  models.Player.findOne({name: req.params.name.toLowerCase()}).remove()
    .then(function (result) {
      if (result.n === 1) {
        req.log.info("Deleted player", req.params.name.toLowerCase());
      }
      res.send({code: "success"});
      return next();
    })
    .catch(next);
};

module.exports.get_series_list = function (req, res, next) {
  var response = {code: "success"};
  models.Series.find()
    .then(function (series) {
      response.series = _.pluck(series, "name");
      res.send(response);
      return next();
    })
    .catch(function (err) {
      req.log.error(err);
      next(err);
    });
};

module.exports.get_series = function (req, res, next) {
  var response = {code: "success"};
  models.Series.findOne({name: req.params.name})
    .populate('players')
    .then(function (series) {
      if (series === null) {
        throw new restify.NotFoundError('Series not found');
      }
      response.series = series.toObject();
      return Promise.all(_.map(series.players, function (p) {
        return p.getStats({days: req.params.stats_days});
      }));
    })
    .then(function (stats) {
      response.series.players = _.map(response.series.players, function (player, index) {
        return {name: player, stats: stats[index]};
      });
      res.send(response);
      return next();
    })
    .catch(function (err) {
      req.log.error(err);
      next(err);
    });
};

module.exports.get_series_games = function (req, res, next) {
  var response = {code: "success"};
  models.Series.findOne({name: req.params.name})
    .then(function (series) {
      if (series === null) {
        throw new restify.NotFoundError('Series not found');
      }
      return models.Game.find({series: series.id})
        .sort({ date: -1 })
        .limit(5)
        .populate('playersAway playersHome winners');
    })
    .then(function (games) {
      response.games = _.map(games, function (game) { return game.toObject(); });
      res.send(response);
      return next();
    })
    .catch(function (err) {
      req.log.error(err);
      next(err);
    });
};

module.exports.create_series = function (req, res, next) {
  var series = new models.Series(req.params);
  series.save()
    .then(function () {
      req.log.info("Added series", series.name);
      res.send({code: "success"});
      return next();
    })
    .catch(models.MongoError, function (err) {
      // Series already exists
      res.send({code: "success"});
      return next();
    })
    .catch(next);
};

module.exports.delete_series = function (req, res, next) {
  var series;
  models.Series.findOne({name: req.params.name})
    .then(function (result) {
      if (!result) {
        res.send({code: "success"});
        return next();
      }
      series = result;
      return models.Game.find({series: series.id}).remove();
    })
    .then(function () {
      return series.remove();
    })
    .then(function (result) {
      if (result.n === 1) {
        req.log.info("deleted series", req.params.name);
      }
      res.send({code: "success"});
      return next();
    })
    .catch(next);
};

module.exports.get_game = function (req, res, next) {
  models.Game.findOne({id: models.Id(req.params.game)})
    .populate('series playersAway playersHome winners')
    .then(function (game) {
      if (game === null) {
        throw new restify.NotFoundError("Game not found");
      }
      res.send({
        code: "success",
        game: game.toObject()
      });
      return next();
    })
    .catch(next);
};

module.exports.add_game = function (req, res, next) {
  var game,
    gameParams,
    gamePromise,
    autoFields = ["teamAway", "teamHome", "goalsAway", "goalsHome"],
    playersAway = req.params.playersAway ? req.params.playersAway.split(',') : [],
    playersHome = req.params.playersHome ? req.params.playersHome.split(',') : [];

  gameParams = _.pick(req.params, autoFields);

  if (!_.isEmpty(req.params.game)) {
    req.log.info("Updating old game", req.params.game);
    gamePromise = models.Game.findOne({id: models.Id(req.params.game)});
  } else {
    gamePromise = Promise.resolve();
  }
  gamePromise
    .then(function (result) {
      if (req.params.game && !result) {
        throw new restify.NotFoundError("Game not found");
      } else {
        game = result || new models.Game(gameParams);
        _.merge(game, gameParams);
        req.log.debug("Game", game);
        return models.Series.findOne({name: req.params.series}).populate('players');
      }
    })
    .then(function (series) {
      if (series === null) {
        throw new restify.NotFoundError('Series not found');
      }
      req.log.debug("Found series", series.name, series.players);
      game.series = series.id;
      game.playersAway = mongoose.Types.Array([]);
      game.playersHome = mongoose.Types.Array([]);
      _.forEach(playersAway, function (name) {
        var playerIndex = _.findIndex(series.players, {name: name.toLowerCase()});
        if (playerIndex === -1) {
          throw new restify.BadRequestError('Player ' + name + ' does not belong to series ' + series.name);
        }
        game.playersAway.push(series.players[playerIndex].id);
      });
      _.forEach(playersHome, function (name) {
        var playerIndex = _.findIndex(series.players, {name: name.toLowerCase()});
        if (playerIndex === -1) {
          throw new restify.BadRequestError('Player ' + name + ' does not belong to series ' + series.name);
        }
        game.playersHome.push(series.players[playerIndex].id);
      });
      return game.save();
    })
    .then(function () {
      req.log.info("Added game", game.id);
      res.send({code: "success", game: game.id});
      return next();
    })
    .catch(models.ValidationError, function (err) {
      req.log.error("Validation failed", err.errors);
      next(err);
    })
    .catch(function (err) {
      req.log.error(err);
      next(err);
    });

};
<commit_msg>Fix updating game<commit_after>/*jslint node: true */
"use strict";

var crypto = require('./crypto');
var models = require('./models');
var mongoose = require('mongoose');
var Promise = require('bluebird');
var restify = require('restify');
var _ = require('lodash');

var roleIsSufficient = function (role, requiredRole) {
  if (requiredRole === "admin") {
    return role === "admin";
  }
  return _.findIndex(["admin", "user"], role) !== -1;
};

module.exports.require_auth = function (requiredRole) {
  return function (req, res, next) {
    if (_.isEmpty(req.headers["x-authentication"])) {
      return next(new restify.ForbiddenError('Authorization required'));
    }
    var tokenString = req.headers["x-authentication"].split(" ")[1];
    models.Token.findOne({token: tokenString})
      .populate(['user'])
      .then(function (token) {
        if (token === null) {
          return next(new restify.ForbiddenError('Permission denied'));
        }
        if (!roleIsSufficient(token.user.role, requiredRole)) {
          return next(new restify.ForbiddenError('Permission denied'));
        }
        return next();
      })
      .catch(function (err) {
        req.log.error(err);
        next(err);
      });
  };
};

module.exports.get_player = function (req, res, next) {
  var response = {code: "success"};
  models.Player.findOne({name: req.params.name.toLowerCase()})
    .populate('series')
    .then(function (player) {
      if (player === null) {
        throw new restify.NotFoundError('Player not found');
      }
      response.player = player.toObject();
      return player.getStats({days: req.params.stats_days});
    })
    .then(function (stats) {
      response.player.stats = stats;
      res.send(response);
      return next();
    })
    .catch(function (err) {
      req.log.error(err);
      next(err);
    });
};

module.exports.create_player = function (req, res, next) {
  var player = new models.Player({displayname: req.params.name, name: req.params.name.toLowerCase()});
  player.save()
    .catch(models.MongoError, function (err) {
      return models.Player.findOne({name: req.params.name.toLowerCase()});
    })
    .then(function (player) {
      req.log.info("Added player", player.name);
      if (!_.isEmpty(req.params.series)) {
        // Maintain two-way link between Player and Series
        req.log.debug("Adding series to player", player.name);
        return models.Series.findOne({name: req.params.series})
          .then(function (series) {
            if (series === null) {
              throw new restify.NotFoundError('Series not found');
            }
            if (_.includes(_.map(series.players, function (v) { return String(v); }), player.id)) {
              return Promise.resolve();
            }
            req.log.debug("Adding player", player.name, "to series", series.name);
            series.players.push(player.id);
            return series.save()
              .catch(function (err) {
                req.log.error(err);
                return next(err);
              });
          })
          .then(function (series) {
            if (series && !player.series.some(function (s) { return s.equals(series.id); })) {
              player.series.push(series.id);
              return player.save();
            } else {
              return Promise.resolve();

            }
          })
          .then(function () {
            // Need to query the model back to get .series populated
            return models.Player.findOne({_id: player.id}).populate('series');
          })
          .then(function (player) {
            res.send({code: "success", player: player.toObject()});
            return next();
          });
      } else {
        res.send({code: "success", player: player.toObject()});
        return next();
      }
    })
    .catch(models.ValidationError, function (err) {
      req.log.error("Validation failed", err.errors);
      next(err);
    })
    .catch(function (err) {
      req.log.error(err);
      next(err);
    });
};

module.exports.create_player_token = function (req, res, next) {
  var player;
  if (_.isEmpty(req.params.password)) {
    throw new restify.BadRequestError('Missing password');
  }
  models.Player.findOne({name: req.params.name.toLowerCase()})
    .then(function (result) {
      if (result === null) {
        throw new restify.NotFoundError('Player not found');
      }
      player = result;
      return crypto.validateUser(player, req.params.password);
    })
    .then(function () {
      var token = new models.Token({user: player.id});
      return token.save();
    })
    .then(function (token) {
      res.send({code: "success", user: player.displayname, token: token.token});
      return next();
    })
    .catch(function (err) {
      req.log.error(err);
      next(err);
    });
};

module.exports.delete_player = function (req, res, next) {
  models.Player.findOne({name: req.params.name.toLowerCase()}).remove()
    .then(function (result) {
      if (result.n === 1) {
        req.log.info("Deleted player", req.params.name.toLowerCase());
      }
      res.send({code: "success"});
      return next();
    })
    .catch(next);
};

module.exports.get_series_list = function (req, res, next) {
  var response = {code: "success"};
  models.Series.find()
    .then(function (series) {
      response.series = _.pluck(series, "name");
      res.send(response);
      return next();
    })
    .catch(function (err) {
      req.log.error(err);
      next(err);
    });
};

module.exports.get_series = function (req, res, next) {
  var response = {code: "success"};
  models.Series.findOne({name: req.params.name})
    .populate('players')
    .then(function (series) {
      if (series === null) {
        throw new restify.NotFoundError('Series not found');
      }
      response.series = series.toObject();
      return Promise.all(_.map(series.players, function (p) {
        return p.getStats({days: req.params.stats_days});
      }));
    })
    .then(function (stats) {
      response.series.players = _.map(response.series.players, function (player, index) {
        return {name: player, stats: stats[index]};
      });
      res.send(response);
      return next();
    })
    .catch(function (err) {
      req.log.error(err);
      next(err);
    });
};

module.exports.get_series_games = function (req, res, next) {
  var response = {code: "success"};
  models.Series.findOne({name: req.params.name})
    .then(function (series) {
      if (series === null) {
        throw new restify.NotFoundError('Series not found');
      }
      return models.Game.find({series: series.id})
        .sort({ date: -1 })
        .limit(5)
        .populate('playersAway playersHome winners');
    })
    .then(function (games) {
      response.games = _.map(games, function (game) { return game.toObject(); });
      res.send(response);
      return next();
    })
    .catch(function (err) {
      req.log.error(err);
      next(err);
    });
};

module.exports.create_series = function (req, res, next) {
  var series = new models.Series(req.params);
  series.save()
    .then(function () {
      req.log.info("Added series", series.name);
      res.send({code: "success"});
      return next();
    })
    .catch(models.MongoError, function (err) {
      // Series already exists
      res.send({code: "success"});
      return next();
    })
    .catch(next);
};

module.exports.delete_series = function (req, res, next) {
  var series;
  models.Series.findOne({name: req.params.name})
    .then(function (result) {
      if (!result) {
        res.send({code: "success"});
        return next();
      }
      series = result;
      return models.Game.find({series: series.id}).remove();
    })
    .then(function () {
      return series.remove();
    })
    .then(function (result) {
      if (result.n === 1) {
        req.log.info("deleted series", req.params.name);
      }
      res.send({code: "success"});
      return next();
    })
    .catch(next);
};

module.exports.get_game = function (req, res, next) {
  models.Game.findById(req.params.game)
    .populate('series playersAway playersHome winners')
    .then(function (game) {
      if (game === null) {
        throw new restify.NotFoundError("Game not found");
      }
      res.send({
        code: "success",
        game: game.toObject()
      });
      return next();
    })
    .catch(next);
};

module.exports.add_game = function (req, res, next) {
  var game,
    gameParams,
    gamePromise,
    autoFields = ["teamAway", "teamHome", "goalsAway", "goalsHome"],
    playersAway = req.params.playersAway ? req.params.playersAway.split(',') : [],
    playersHome = req.params.playersHome ? req.params.playersHome.split(',') : [];

  gameParams = _.pick(req.params, autoFields);

  if (!_.isEmpty(req.params.game)) {
    req.log.info("Updating old game", req.params.game);
    gamePromise = models.Game.findById(req.params.game);
  } else {
    gamePromise = Promise.resolve();
  }
  gamePromise
    .then(function (result) {
      if (req.params.game && !result) {
        throw new restify.NotFoundError("Game not found");
      } else {
        game = result || new models.Game(gameParams);
        _.merge(game, gameParams);
        req.log.debug("Game", game);
        return models.Series.findOne({name: req.params.series}).populate('players');
      }
    })
    .then(function (series) {
      if (series === null) {
        throw new restify.NotFoundError('Series not found');
      }
      req.log.debug("Found series", series.name, series.players);
      game.series = series.id;
      game.playersAway = mongoose.Types.Array([]);
      game.playersHome = mongoose.Types.Array([]);
      _.forEach(playersAway, function (name) {
        var playerIndex = _.findIndex(series.players, {name: name.toLowerCase()});
        if (playerIndex === -1) {
          throw new restify.BadRequestError('Player ' + name + ' does not belong to series ' + series.name);
        }
        game.playersAway.push(series.players[playerIndex].id);
      });
      _.forEach(playersHome, function (name) {
        var playerIndex = _.findIndex(series.players, {name: name.toLowerCase()});
        if (playerIndex === -1) {
          throw new restify.BadRequestError('Player ' + name + ' does not belong to series ' + series.name);
        }
        game.playersHome.push(series.players[playerIndex].id);
      });
      return game.save();
    })
    .then(function () {
      req.log.info("Added game", game.id);
      res.send({code: "success", game: game.id});
      return next();
    })
    .catch(models.ValidationError, function (err) {
      req.log.error("Validation failed", err.errors);
      next(err);
    })
    .catch(function (err) {
      req.log.error(err);
      next(err);
    });

};
<|endoftext|>


<commit_before>chrome.storage.sync.get({
	showHeaderBackgroundImage: false
	}, function(items) {

		if (!items.showHeaderBackgroundImage) {
			adjustWithoutBGImage()
		}
		else {
			var gamePrimaryDivs = document.getElementsByClassName("game-header");
			for(var i = 0; i < gamePrimaryDivs.length; i++) {
				var item = gamePrimaryDivs.item(i)
					item.setAttribute('style', 'background-image: -webkit-linear-gradient(-360deg, #080912 60%, rgba(0, 0, 0, 0.55) 100%) !important');
			}
		}

		makeTopDivVisible();
});

function adjustWithoutBGImage() {
	var gamePrimaryDivs = document.getElementsByClassName("game-primary");
			for(var i = 0; i < gamePrimaryDivs.length; i++) {
				var item = gamePrimaryDivs.item(i)
				item.style["background-image"]='none';
				item.style["background-color"]='transparent';
			}

			var gameHeaderTitle = document.getElementsByClassName("game-header-title-info");
			for(var i = 0; i < gameHeaderTitle.length; i++) {
				var item = gameHeaderTitle.item(i)
				item.style["color"]='rgb(0, 0, 136)';
				item.style["font-weight"]='bold';
				item.style["font-size"]='22px';
			}

			var gameHeaderItems = document.getElementsByClassName("game-header");
			for(var i = 0; i < gameHeaderItems.length; i++) {
				var item = gameHeaderItems.item(i)
				item.style["color"]='black';
				item.style["background"]='transparent';
			}

			var credits = document.getElementsByClassName("credits");
			for(var i = 0; i < credits.length; i++) {
				var item = credits.item(i)
				item.style["border-top-color"]='rgb(128, 128, 128)';
				item.style["border-bottom-color"]='rgb(128, 128, 128)';
				item.style["background-color"]='rgb(229, 229, 229)';
			}

			var titleContainer = document.getElementsByClassName("game-header-title-container");
			for(var i = 0; i < titleContainer.length; i++) {
				var item = titleContainer.item(i)
				item.style["border-style"]='solid';
				item.style["border-width"]='2px';
				item.style["border-color"]='rgb(212, 218, 232)';
				item.style["background-color"]='rgb(236, 239, 246)';
			}

			var gameHeaderCollapsed = document.getElementsByClassName("game-header-credits hidden-game-header-collapsed");
			for(var i = 0; i < gameHeaderCollapsed.length; i++) {
				var item = gameHeaderCollapsed.item(i)
				item.style["margin-top"]='0px';
			}

			var primaryActionsGameHeaderCollapsed = document.getElementsByClassName("game-header-primary-actions hidden-game-header-collapsed");
			for(var i = 0; i < primaryActionsGameHeaderCollapsed.length; i++) {
				var item = primaryActionsGameHeaderCollapsed.item(i)
				item.style["background-color"]='white';
			}

			var gameHeaderBody = document.getElementsByClassName("game-header-body");
			for(var i = 0; i < gameHeaderBody.length; i++) {
				var item = gameHeaderBody.item(i)
				item.style["background-color"]='white';
			}

			var spanRatingStars = document.getElementsByClassName("rating-stars");
			for(var i = 0; i < spanRatingStars.length; i++) {
				var item = spanRatingStars.item(i)
				item.style["background-color"]='#dbe0e5';
			}
}

function makeTopDivVisible() {
	var gamePrimaryDivs = document.getElementsByClassName("game-primary");
	for(var i = 0; i < gamePrimaryDivs.length; i++) {
		var item = gamePrimaryDivs.item(i)
		item.style["visibility"]="visible";
	}
}<commit_msg>- Refactored.<commit_after>chrome.storage.sync.get({
	showHeaderBackgroundImage: false
	}, function(items) {

		if (!items.showHeaderBackgroundImage) {
			adjustWithoutBGImage()
		}
		else {
			var gamePrimaryDivs = document.getElementsByClassName("game-header");
			for(var i = 0; i < gamePrimaryDivs.length; i++) {
				var item = gamePrimaryDivs.item(i)
					item.setAttribute('style', 'background-image: -webkit-linear-gradient(-360deg, #080912 60%, rgba(0, 0, 0, 0.55) 100%) !important');
			}
		}

		makeTopDivVisible()
});

function adjustWithoutBGImage() {
	var gamePrimaryDivs = document.getElementsByClassName("game-primary");
			for(var i = 0; i < gamePrimaryDivs.length; i++) {
				var item = gamePrimaryDivs.item(i)
				item.style["background-image"]='none';
				item.style["background-color"]='transparent';
			}

			var gameHeaderTitle = document.getElementsByClassName("game-header-title-info");
			for(var i = 0; i < gameHeaderTitle.length; i++) {
				var item = gameHeaderTitle.item(i)
				item.style["color"]='rgb(0, 0, 136)';
				item.style["font-weight"]='bold';
				item.style["font-size"]='22px';
			}

			var gameHeaderItems = document.getElementsByClassName("game-header");
			for(var i = 0; i < gameHeaderItems.length; i++) {
				var item = gameHeaderItems.item(i)
				item.style["color"]='black';
				item.style["background"]='transparent';
			}

			var credits = document.getElementsByClassName("credits");
			for(var i = 0; i < credits.length; i++) {
				var item = credits.item(i)
				item.style["border-top-color"]='rgb(128, 128, 128)';
				item.style["border-bottom-color"]='rgb(128, 128, 128)';
				item.style["background-color"]='rgb(229, 229, 229)';
			}

			var titleContainer = document.getElementsByClassName("game-header-title-container");
			for(var i = 0; i < titleContainer.length; i++) {
				var item = titleContainer.item(i)
				item.style["border-style"]='solid';
				item.style["border-width"]='2px';
				item.style["border-color"]='rgb(212, 218, 232)';
				item.style["background-color"]='rgb(236, 239, 246)';
			}

			var gameHeaderCollapsed = document.getElementsByClassName("game-header-credits hidden-game-header-collapsed");
			for(var i = 0; i < gameHeaderCollapsed.length; i++) {
				var item = gameHeaderCollapsed.item(i)
				item.style["margin-top"]='0px';
			}

			var primaryActionsGameHeaderCollapsed = document.getElementsByClassName("game-header-primary-actions hidden-game-header-collapsed");
			for(var i = 0; i < primaryActionsGameHeaderCollapsed.length; i++) {
				var item = primaryActionsGameHeaderCollapsed.item(i)
				item.style["background-color"]='white';
			}

			var gameHeaderBody = document.getElementsByClassName("game-header-body");
			for(var i = 0; i < gameHeaderBody.length; i++) {
				var item = gameHeaderBody.item(i)
				item.style["background-color"]='white';
			}

			var spanRatingStars = document.getElementsByClassName("rating-stars");
			for(var i = 0; i < spanRatingStars.length; i++) {
				var item = spanRatingStars.item(i)
				item.style["background-color"]='#dbe0e5';
			}
}

function makeTopDivVisible() {
	var gamePrimaryDivs = document.getElementsByClassName("game-primary");
	for(var i = 0; i < gamePrimaryDivs.length; i++) {
		var item = gamePrimaryDivs.item(i)
		item.style["visibility"]="visible";
	}
}<|endoftext|>


<commit_before>'use strict';

var _            = require('lodash');
var Promise      = require('./promise');

// The "Runner" constructor takes a "builder" (query, schema, or raw)
// and runs through each of the query statements, calling any additional
// "output" method provided alongside the query and bindings.
function Runner(builder) {
  this.builder = builder;
  this.queries = [];

  // The "connection" object is set on the runner when
  // "run" is called.
  this.connection = void 0;
}

Runner.prototype._beginTransaction = 'begin;';
Runner.prototype._commitTransaction = 'commit;';
Runner.prototype._rollbackTransaction = 'rollback;';

// "Run" the target, calling "toSQL" on the builder, returning
// an object or array of queries to run, each of which are run on
// a single connection.
Runner.prototype.run = Promise.method(function() {
  if (this.builder._transacting) {
    return this.transactionQuery();
  }
  return Promise.bind(this)
    .then(this.ensureConnection)
    .then(function(connection) {
      this.connection = connection;

      // Emit a "start" event on both the builder and the client,
      // allowing us to listen in on any events. We fire on the "client"
      // before building the SQL, and on the builder after building the SQL
      // in case we want to determine at how long it actually
      // took to build the query.
      this.client.emit('start', this.builder);
      var sql = this.builder.toSQL();

      if (_.isArray(sql)) {
        return this.queryArray(sql);
      }
      return this.query(sql);
    })
    .then(function (data) {
      return this.builder.runHook('after', data);
    })

    // If there are any "error" listeners, we fire an error event
    // and then re-throw the error to be eventually handled by
    // the promise chain. Useful if you're wrapping in a custom `Promise`.
    .catch(function(err) {
      if (this.builder._events && this.builder._events.error) {
        this.builder.emit('error', err);
      }
      throw err;
    })

    // Fire a single "end" event on the builder when
    // all queries have successfully completed.
    .tap(function() {
      this.builder.emit('end');
    })
    .finally(this.cleanupConnection);
});

// Stream the result set, by passing through to the dialect's streaming
// capabilities. If the options are
var PassThrough;
Runner.prototype.stream = function(options, handler) {
  // If we specify stream(handler).then(...
  if (arguments.length === 1) {
    if (_.isFunction(options)) {
      handler = options;
      options = {};
    }
  }

  // Determines whether we emit an error or throw here.
  var hasHandler = _.isFunction(handler);

  // Lazy-load the "PassThrough" dependency.
  PassThrough = PassThrough || require('readable-stream').PassThrough;
  var stream  = new PassThrough({objectMode: true});
  var promise = Promise.bind(this)
    .then(this.ensureConnection)
    .then(function(connection) {
      this.connection = connection;
      var sql = this.builder.toSQL();
      var err = new Error('The stream may only be used with a single query statement.');
      if (_.isArray(sql)) {
        if (hasHandler) throw err;
        stream.emit('error', err);
      }
      return sql;
    }).then(function(sql) {
      return this._stream(sql, stream, options);
    }).finally(this.cleanupConnection);

  // If a function is passed to handle the stream, send the stream
  // there and return the promise, otherwise just return the stream
  // and the promise will take care of itsself.
  if (hasHandler) {
    handler(stream);
    return promise;
  }
  return stream;
};

// Allow you to pipe the stream to a writable stream.
Runner.prototype.pipe = function(writable) {
  return this.stream().pipe(writable);
};

// "Runs" a query, returning a promise. All queries specified by the builder are guaranteed
// to run in sequence, and on the same connection, especially helpful when schema building
// and dealing with foreign key constraints, etc.
Runner.prototype.query = Promise.method(function(obj) {
  if (!this.connection) {
    throw new Error('There is an error with the database connection. Please check your config.');
  }
  obj.__cid = this.connection.__cid;
  this.builder.emit('query', obj);
  this.client.emit('query', obj);
  return this._query(obj).bind(this).then(this.processResponse);
});

// In the case of the "schema builder" we call `queryArray`, which runs each
// of the queries in sequence.
Runner.prototype.queryArray = Promise.method(function(queries) {
  return queries.length === 1 ? this.query(queries[0]) : Promise.bind(this)
    .thenReturn(queries)
    .reduce(function(memo, query) {
      return this.query(query).then(function(resp) {
        memo.push(resp);
        return memo;
      });
    }, []);
});

// Check whether there's a transaction flag, and that it has a connection.
Runner.prototype.ensureConnection = Promise.method(function() {
  if (this.builder._connection) {
    return this.builder._connection;
  }
  return this.client.acquireConnection();
});

// "Debug" the query being run.
Runner.prototype.debug = function(obj) {
  console.dir(_.extend({__cid: this.connection.__cid}, obj));
};

// Check whether we're "debugging", based on either calling `debug` on the query.
Runner.prototype.isDebugging = function() {
  return (this.client.isDebugging === true || this.builder._debug === true);
};

// Transaction Methods:
// -------

// Run the transaction on the correct "runner" instance.
Runner.prototype.transactionQuery = Promise.method(function() {
  var runner = this.builder._transacting._runner;
  if (!(runner instanceof Runner)) {
    throw new Error('Invalid transaction object provided.');
  }
  var sql = this.builder.toSQL();
  if (_.isArray(sql)) {
    return runner.queryArray(sql);
  }
  return runner.query(sql);
});

// Begins a transaction statement on the instance,
// resolving with the current runner.
Runner.prototype.startTransaction = Promise.method(function() {
  return Promise.bind(this)
    .then(this.ensureConnection)
    .then(function(connection) {
      this.connection  = connection;
      this.transaction = true;
      return this.beginTransaction();
    }).thenReturn(this);
});

// Finishes the transaction statement and handles disposing of the connection,
// resolving / rejecting the transaction's promise, and ensuring the transaction object's
// `_runner` property is `null`'ed out so it cannot continue to be used.
Runner.prototype.finishTransaction = Promise.method(function(action, containerObject, msg) {
  var query, dfd = containerObject.__dfd__;

  // Run the query to commit / rollback the transaction.
  switch (action) {
    case 0:
      query = this.commitTransaction();
      break;
    case 1:
      query = this.rollbackTransaction();
      break;
  }

  return query.then(function(resp) {
    msg = (msg === void 0) ? resp : msg;
    switch (action) {
      case 0:
        dfd.fulfill(msg);
        break;
      case 1:
        dfd.reject(msg);
        break;
    }

  // If there was a problem committing the transaction,
  // reject the transaction block (to reject the entire transaction block),
  // then re-throw the error for any promises chained off the commit.
  }).catch(function(e) {
    dfd.reject(e);
    throw e;
  }).bind(this).finally(function() {

    // Kill the "_runner" object on the containerObject,
    // so it's not possible to continue using the transaction object.
    containerObject._runner = void 0;

    return this.cleanupConnection();
  });
});

Runner.prototype.beginTransaction = function() {
  return this._beginTransaction   && this.query({sql: this._beginTransaction});
};
Runner.prototype.commitTransaction = function() {
  return this._commitTransaction   && this.query({sql: this._commitTransaction});
};
Runner.prototype.rollbackTransaction = function() {
  return this._rollbackTransaction && this.query({sql: this._rollbackTransaction});
};

// Cleanup the connection as necessary, if the `_connection` was
// explicitly set on the query we don't need to do anything here,
// otherwise we
Runner.prototype.cleanupConnection = Promise.method(function() {
  if (!this.builder._connection && typeof this.connection !== "undefined") {
    return this.client.releaseConnection(this.connection);
  }
});

module.exports = Runner;
<commit_msg>Fix whitespace<commit_after>'use strict';

var _            = require('lodash');
var Promise      = require('./promise');

// The "Runner" constructor takes a "builder" (query, schema, or raw)
// and runs through each of the query statements, calling any additional
// "output" method provided alongside the query and bindings.
function Runner(builder) {
  this.builder = builder;
  this.queries = [];

  // The "connection" object is set on the runner when
  // "run" is called.
  this.connection = void 0;
}

Runner.prototype._beginTransaction = 'begin;';
Runner.prototype._commitTransaction = 'commit;';
Runner.prototype._rollbackTransaction = 'rollback;';

// "Run" the target, calling "toSQL" on the builder, returning
// an object or array of queries to run, each of which are run on
// a single connection.
Runner.prototype.run = Promise.method(function() {
  if (this.builder._transacting) {
    return this.transactionQuery();
  }
  return Promise.bind(this)
    .then(this.ensureConnection)
    .then(function(connection) {
      this.connection = connection;

      // Emit a "start" event on both the builder and the client,
      // allowing us to listen in on any events. We fire on the "client"
      // before building the SQL, and on the builder after building the SQL
      // in case we want to determine at how long it actually
      // took to build the query.
      this.client.emit('start', this.builder);
      var sql = this.builder.toSQL();

      if (_.isArray(sql)) {
        return this.queryArray(sql);
      }
      return this.query(sql);
    })
    .then(function (data) {
      return this.builder.runHook('after', data);
    })

    // If there are any "error" listeners, we fire an error event
    // and then re-throw the error to be eventually handled by
    // the promise chain. Useful if you're wrapping in a custom `Promise`.
    .catch(function(err) {
      if (this.builder._events && this.builder._events.error) {
        this.builder.emit('error', err);
      }
      throw err;
    })

    // Fire a single "end" event on the builder when
    // all queries have successfully completed.
    .tap(function() {
      this.builder.emit('end');
    })
    .finally(this.cleanupConnection);
});

// Stream the result set, by passing through to the dialect's streaming
// capabilities. If the options are
var PassThrough;
Runner.prototype.stream = function(options, handler) {
  // If we specify stream(handler).then(...
  if (arguments.length === 1) {
    if (_.isFunction(options)) {
      handler = options;
      options = {};
    }
  }

  // Determines whether we emit an error or throw here.
  var hasHandler = _.isFunction(handler);

  // Lazy-load the "PassThrough" dependency.
  PassThrough = PassThrough || require('readable-stream').PassThrough;
  var stream  = new PassThrough({objectMode: true});
  var promise = Promise.bind(this)
    .then(this.ensureConnection)
    .then(function(connection) {
      this.connection = connection;
      var sql = this.builder.toSQL();
      var err = new Error('The stream may only be used with a single query statement.');
      if (_.isArray(sql)) {
        if (hasHandler) throw err;
        stream.emit('error', err);
      }
      return sql;
    }).then(function(sql) {
      return this._stream(sql, stream, options);
    }).finally(this.cleanupConnection);

  // If a function is passed to handle the stream, send the stream
  // there and return the promise, otherwise just return the stream
  // and the promise will take care of itsself.
  if (hasHandler) {
    handler(stream);
    return promise;
  }
  return stream;
};

// Allow you to pipe the stream to a writable stream.
Runner.prototype.pipe = function(writable) {
  return this.stream().pipe(writable);
};

// "Runs" a query, returning a promise. All queries specified by the builder are guaranteed
// to run in sequence, and on the same connection, especially helpful when schema building
// and dealing with foreign key constraints, etc.
Runner.prototype.query = Promise.method(function(obj) {
  if (!this.connection) {
    throw new Error('There is an error with the database connection. Please check your config.');
  }
  obj.__cid = this.connection.__cid;
  this.builder.emit('query', obj);
  this.client.emit('query', obj);
  return this._query(obj).bind(this).then(this.processResponse);
});

// In the case of the "schema builder" we call `queryArray`, which runs each
// of the queries in sequence.
Runner.prototype.queryArray = Promise.method(function(queries) {
  return queries.length === 1 ? this.query(queries[0]) : Promise.bind(this)
    .thenReturn(queries)
    .reduce(function(memo, query) {
      return this.query(query).then(function(resp) {
        memo.push(resp);
        return memo;
      });
    }, []);
});

// Check whether there's a transaction flag, and that it has a connection.
Runner.prototype.ensureConnection = Promise.method(function() {
  if (this.builder._connection) {
    return this.builder._connection;
  }
  return this.client.acquireConnection();
});

// "Debug" the query being run.
Runner.prototype.debug = function(obj) {
  console.dir(_.extend({__cid: this.connection.__cid}, obj));
};

// Check whether we're "debugging", based on either calling `debug` on the query.
Runner.prototype.isDebugging = function() {
  return (this.client.isDebugging === true || this.builder._debug === true);
};

// Transaction Methods:
// -------

// Run the transaction on the correct "runner" instance.
Runner.prototype.transactionQuery = Promise.method(function() {
  var runner = this.builder._transacting._runner;
  if (!(runner instanceof Runner)) {
    throw new Error('Invalid transaction object provided.');
  }
  var sql = this.builder.toSQL();
  if (_.isArray(sql)) {
    return runner.queryArray(sql);
  }
  return runner.query(sql);
});

// Begins a transaction statement on the instance,
// resolving with the current runner.
Runner.prototype.startTransaction = Promise.method(function() {
  return Promise.bind(this)
    .then(this.ensureConnection)
    .then(function(connection) {
      this.connection  = connection;
      this.transaction = true;
      return this.beginTransaction();
    }).thenReturn(this);
});

// Finishes the transaction statement and handles disposing of the connection,
// resolving / rejecting the transaction's promise, and ensuring the transaction object's
// `_runner` property is `null`'ed out so it cannot continue to be used.
Runner.prototype.finishTransaction = Promise.method(function(action, containerObject, msg) {
  var query, dfd = containerObject.__dfd__;

  // Run the query to commit / rollback the transaction.
  switch (action) {
    case 0:
      query = this.commitTransaction();
      break;
    case 1:
      query = this.rollbackTransaction();
      break;
  }

  return query.then(function(resp) {
    msg = (msg === void 0) ? resp : msg;
    switch (action) {
      case 0:
        dfd.fulfill(msg);
        break;
      case 1:
        dfd.reject(msg);
        break;
    }

  // If there was a problem committing the transaction,
  // reject the transaction block (to reject the entire transaction block),
  // then re-throw the error for any promises chained off the commit.
  }).catch(function(e) {
    dfd.reject(e);
    throw e;
  }).bind(this).finally(function() {

    // Kill the "_runner" object on the containerObject,
    // so it's not possible to continue using the transaction object.
    containerObject._runner = void 0;

    return this.cleanupConnection();
  });
});

Runner.prototype.beginTransaction = function() {
  return this._beginTransaction   && this.query({sql: this._beginTransaction});
};
Runner.prototype.commitTransaction = function() {
  return this._commitTransaction   && this.query({sql: this._commitTransaction});
};
Runner.prototype.rollbackTransaction = function() {
  return this._rollbackTransaction && this.query({sql: this._rollbackTransaction});
};

// Cleanup the connection as necessary, if the `_connection` was
// explicitly set on the query we don't need to do anything here,
// otherwise we
Runner.prototype.cleanupConnection = Promise.method(function() {
  if (!this.builder._connection && typeof this.connection !== "undefined") {
    return this.client.releaseConnection(this.connection);
  }
});

module.exports = Runner;
<|endoftext|>


<commit_before>var async = require('async');
var Step = require('step');
var _ = require('lodash');
var path = require('path');
var fs = require('fs');
var db = require('./db');
var Migration = require('./migration');

module.exports = function MigrationRunner(options){
  var self = this;

  var migrations = [];
  loadMigrationFiles();

  db.init(options.database_url);

  self.run = function(callback){
    var current_index, migrate_to_index;
    Step(
      function(){
        ensureMigrationTableExists(this);
      },
      function fetchCompletedMigrations(err){
        db.query("SELECT * FROM "+options.migrations_table+" ORDER BY run_on", this)
      },
	    function determineMigrationsToRun(err, result){
		    if (err) return callback(err);
		    if (!result || !result.rows) return callback(new Error('Unable to fetch migrations from pgmigrations table'));

		    //store done migration names
		    var runNames = result.rows.map(function(row){
			    return row.name;
		    });

		    var doneMigrations = [];
		    var runMigrations = [];

				//filter out undone and done migrations from list of files
		    for (var i=0; i<migrations.length; i++){
			    if ( runNames.indexOf(migrations[i].name) < 0 ){

				    //if specific migration file is requested
				    if (options.file && options.file == migrations[i].name){
					    runMigrations = [migrations[i]];
					    break;
				    }
				    runMigrations.push(migrations[i]);
			    }else{
				    doneMigrations.push(migrations[i])
			    }

		    }

				//final selection will go here
		    var to_run;

		    //down gets by default one migration at the time, if not set otherwise
		    if(options.direction=='down'){
			    to_run = doneMigrations.slice(-1);
			  //up gets all undone migrations by default
		    }else{
			    to_run = runMigrations;
		    }

		    //if specific count of migrations is requested
		    if (options.count){
			    // infinity is set in the bin file
			    if (options.count !== Infinity){
				    if(options.direction=='up'){
					    to_run = runMigrations.slice(0, options.count);
				    }else{
					    to_run = doneMigrations.slice(options.count * -1);
				    }
			    }
		    }

		    if (!to_run.length) {
			    console.log('No migrations to run!');
			    return callback();
		    }

		    // TODO: add some fancy colors to logging
		    console.log('> Migrating files:' );
		    for(var i in to_run){
			    console.log('> - ' + to_run[i].name );
		    }

		    this(null, to_run);
	    },
      function runMigrations(err, migrations_to_run){
        if (err) return callback(err);
        async.eachSeries(migrations_to_run, function(m, next){
          if (options.direction == 'up') m.applyUp(next);
          else m.applyDown(next);
        }, this);
      },
      function finish(err){
        if (err) {
          console.log('> Rolling back attempted migration ...')
          return callback(err);
        }
        callback();
      }
    )
  }

  function loadMigrationFiles(){
    fs.readdirSync( options.dir + '/' ).forEach(function(file) {
      if (file.match(/.+\.js$/g) !== null && file !== 'index.js') {
        var name = file.replace('.js', '');
        // console.log( '> loading migration: '+name)
        var file_path = options.dir +'/'+ file;
        var actions = require( path.relative(__dirname, file_path) );
        var migration = new Migration( file_path, actions, options );
        migrations.push(migration);
      }
    });
    migrations = _.sortBy(migrations, 'name');
  }

  function ensureMigrationTableExists(callback){
    Step(
      function checkIfTableExists(){
        db.query("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name = '"+options.migrations_table+"'", this);
      },
      function createTableIfNecessary(err, result){
        if (err) return callback(err);
        if (result && result.rows && result.rows.length == 1) return callback();
        db.query('CREATE TABLE '+options.migrations_table+' ( id SERIAL, name varchar(255) NOT NULL, run_on timestamp NOT NULL)', this);
      },
      function finish(err){
        if (err) return callback(err);
        return callback();
      }
    )
  }

}

<commit_msg>Fixed tabbing<commit_after>var async = require('async');
var Step = require('step');
var _ = require('lodash');
var path = require('path');
var fs = require('fs');
var db = require('./db');
var Migration = require('./migration');

module.exports = function MigrationRunner(options){
  var self = this;

  var migrations = [];
  loadMigrationFiles();

  db.init(options.database_url);

  self.run = function(callback){
    var current_index, migrate_to_index;
    Step(
      function(){
        ensureMigrationTableExists(this);
      },
      function fetchCompletedMigrations(err){
        db.query("SELECT * FROM "+options.migrations_table+" ORDER BY run_on", this)
      },
      function determineMigrationsToRun(err, result) {
        if(err) return callback(err);
        if(!result || !result.rows) return callback(new Error('Unable to fetch migrations from pgmigrations table'));

        //store done migration names
        var runNames = result.rows.map(function(row) {
          return row.name;
        });

        var doneMigrations = [];
        var runMigrations = [];

        //filter out undone and done migrations from list of files
        for(var i = 0; i < migrations.length; i++) {
          if(runNames.indexOf(migrations[i].name) < 0) {

            //if specific migration file is requested
            if(options.file && options.file == migrations[i].name) {
              runMigrations = [migrations[i]];
              break;
            }
            runMigrations.push(migrations[i]);
          } else {
            doneMigrations.push(migrations[i])
          }

        }

        //final selection will go here
        var to_run;

        //down gets by default one migration at the time, if not set otherwise
        if(options.direction == 'down') {
          to_run = doneMigrations.slice(-1);
          //up gets all undone migrations by default
        } else {
          to_run = runMigrations;
        }

        //if specific count of migrations is requested
        if(options.count) {
          // infinity is set in the bin file
          if(options.count !== Infinity) {
            if(options.direction == 'up') {
              to_run = runMigrations.slice(0, options.count);
            } else {
              to_run = doneMigrations.slice(options.count * -1);
            }
          }
        }

        if(!to_run.length) {
          console.log('No migrations to run!');
          return callback();
        }

        // TODO: add some fancy colors to logging
        console.log('> Migrating files:');
        for(var i in to_run) {
          console.log('> - ' + to_run[i].name);
        }

        this(null, to_run);
      },
      function runMigrations(err, migrations_to_run){
        if (err) return callback(err);
        async.eachSeries(migrations_to_run, function(m, next){
          if (options.direction == 'up') m.applyUp(next);
          else m.applyDown(next);
        }, this);
      },
      function finish(err){
        if (err) {
          console.log('> Rolling back attempted migration ...')
          return callback(err);
        }
        callback();
      }
    )
  }

  function loadMigrationFiles(){
    fs.readdirSync( options.dir + '/' ).forEach(function(file) {
      if (file.match(/.+\.js$/g) !== null && file !== 'index.js') {
        var name = file.replace('.js', '');
        // console.log( '> loading migration: '+name)
        var file_path = options.dir +'/'+ file;
        var actions = require( path.relative(__dirname, file_path) );
        var migration = new Migration( file_path, actions, options );
        migrations.push(migration);
      }
    });
    migrations = _.sortBy(migrations, 'name');
  }

  function ensureMigrationTableExists(callback){
    Step(
      function checkIfTableExists(){
        db.query("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name = '"+options.migrations_table+"'", this);
      },
      function createTableIfNecessary(err, result){
        if (err) return callback(err);
        if (result && result.rows && result.rows.length == 1) return callback();
        db.query('CREATE TABLE '+options.migrations_table+' ( id SERIAL, name varchar(255) NOT NULL, run_on timestamp NOT NULL)', this);
      },
      function finish(err){
        if (err) return callback(err);
        return callback();
      }
    )
  }

}

<|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */

var EventEmitter = require('events').EventEmitter
  , debug = require('debug')('mocha:runner')
  , Test = require('./test')
  , utils = require('./utils')
  , filter = utils.filter
  , keys = utils.keys;

/**
 * Non-enumerable globals.
 */

var globals = [
  'setTimeout',
  'clearTimeout',
  'setInterval',
  'clearInterval',
  'XMLHttpRequest',
  'Date'
];

/**
 * Expose `Runner`.
 */

module.exports = Runner;

/**
 * Initialize a `Runner` for the given `suite`.
 *
 * Events:
 *
 *   - `start`  execution started
 *   - `end`  execution complete
 *   - `suite`  (suite) test suite execution started
 *   - `suite end`  (suite) all tests (and sub-suites) have finished
 *   - `test`  (test) test execution started
 *   - `test end`  (test) test completed
 *   - `hook`  (hook) hook execution started
 *   - `hook end`  (hook) hook complete
 *   - `pass`  (test) test passed
 *   - `fail`  (test, err) test failed
 *
 * @api public
 */

function Runner(suite) {
  var self = this;
  this._globals = [];
  this.suite = suite;
  this.total = suite.total();
  this.failures = 0;
  this.on('test end', function(test){ self.checkGlobals(test); });
  this.on('hook end', function(hook){ self.checkGlobals(hook); });
  this.grep(/.*/);
  this.globals(this.globalProps().concat(['errno']));
}

/**
 * Wrapper for setImmediate, process.nextTick, or browser polyfill.
 *
 * @param {Function} fn
 * @api private
 */

Runner.immediately = global.setImmediate || process.nextTick;

/**
 * Inherit from `EventEmitter.prototype`.
 */

Runner.prototype.__proto__ = EventEmitter.prototype;

/**
 * Run tests with full titles matching `re`. Updates runner.total
 * with number of tests matched.
 *
 * @param {RegExp} re
 * @param {Boolean} invert
 * @return {Runner} for chaining
 * @api public
 */

Runner.prototype.grep = function(re, invert){
  debug('grep %s', re);
  this._grep = re;
  this._invert = invert;
  this.total = this.grepTotal(this.suite);
  return this;
};

/**
 * Returns the number of tests matching the grep search for the
 * given suite.
 *
 * @param {Suite} suite
 * @return {Number}
 * @api public
 */

Runner.prototype.grepTotal = function(suite) {
  var self = this;
  var total = 0;

  suite.eachTest(function(test){
    var match = self._grep.test(test.fullTitle());
    if (self._invert) match = !match;
    if (match) total++;
  });

  return total;
};

/**
 * Return a list of global properties.
 *
 * @return {Array}
 * @api private
 */

Runner.prototype.globalProps = function() {
  var props = utils.keys(global);

  // non-enumerables
  for (var i = 0; i < globals.length; ++i) {
    if (~utils.indexOf(props, globals[i])) continue;
    props.push(globals[i]);
  }

  return props;
};

/**
 * Allow the given `arr` of globals.
 *
 * @param {Array} arr
 * @return {Runner} for chaining
 * @api public
 */

Runner.prototype.globals = function(arr){
  if (0 == arguments.length) return this._globals;
  debug('globals %j', arr);
  utils.forEach(arr, function(arr){
    this._globals.push(arr);
  }, this);
  return this;
};

/**
 * Check for global variable leaks.
 *
 * @api private
 */

Runner.prototype.checkGlobals = function(test){
  if (this.ignoreLeaks) return;
  var ok = this._globals;
  var globals = this.globalProps();
  var isNode = process.kill;
  var leaks;

  // check length - 2 ('errno' and 'location' globals)
  if (isNode && 1 == ok.length - globals.length) return
  else if (2 == ok.length - globals.length) return;

  leaks = filterLeaks(ok, globals);
  this._globals = this._globals.concat(leaks);

  if (leaks.length > 1) {
    this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + ''));
  } else if (leaks.length) {
    this.fail(test, new Error('global leak detected: ' + leaks[0]));
  }
};

/**
 * Fail the given `test`.
 *
 * @param {Test} test
 * @param {Error} err
 * @api private
 */

Runner.prototype.fail = function(test, err){
  ++this.failures;
  test.state = 'failed';

  if ('string' == typeof err) {
    err = new Error('the string "' + err + '" was thrown, throw an Error :)');
  }

  this.emit('fail', test, err);
};

/**
 * Fail the given `hook` with `err`.
 *
 * Hook failures (currently) hard-end due
 * to that fact that a failing hook will
 * surely cause subsequent tests to fail,
 * causing jumbled reporting.
 *
 * @param {Hook} hook
 * @param {Error} err
 * @api private
 */

Runner.prototype.failHook = function(hook, err){
  this.fail(hook, err);
  this.emit('end');
};

/**
 * Run hook `name` callbacks and then invoke `fn()`.
 *
 * @param {String} name
 * @param {Function} function
 * @api private
 */

Runner.prototype.hook = function(name, fn){
  var suite = this.suite
    , hooks = suite['_' + name]
    , self = this
    , timer;

  function next(i) {
    var hook = hooks[i];
    if (!hook) return fn();
    if (self.failures && suite.bail()) return fn();
    self.currentRunnable = hook;

    self.emit('hook', hook);

    hook.on('error', function(err){
      self.failHook(hook, err);
    });

    hook.run(function(err){
      hook.removeAllListeners('error');
      var testError = hook.error();
      if (testError) self.fail(self.test, testError);
      if (err) return self.failHook(hook, err);
      self.emit('hook end', hook);
      next(++i);
    });
  }

  Runner.immediately(function(){
    next(0);
  });
};

/**
 * Run hook `name` for the given array of `suites`
 * in order, and callback `fn(err)`.
 *
 * @param {String} name
 * @param {Array} suites
 * @param {Function} fn
 * @api private
 */

Runner.prototype.hooks = function(name, suites, fn){
  var self = this
    , orig = this.suite;

  function next(suite) {
    self.suite = suite;

    if (!suite) {
      self.suite = orig;
      return fn();
    }

    self.hook(name, function(err){
      if (err) {
        self.suite = orig;
        return fn(err);
      }

      next(suites.pop());
    });
  }

  next(suites.pop());
};

/**
 * Run hooks from the top level down.
 *
 * @param {String} name
 * @param {Function} fn
 * @api private
 */

Runner.prototype.hookUp = function(name, fn){
  var suites = [this.suite].concat(this.parents()).reverse();
  this.hooks(name, suites, fn);
};

/**
 * Run hooks from the bottom up.
 *
 * @param {String} name
 * @param {Function} fn
 * @api private
 */

Runner.prototype.hookDown = function(name, fn){
  var suites = [this.suite].concat(this.parents());
  this.hooks(name, suites, fn);
};

/**
 * Return an array of parent Suites from
 * closest to furthest.
 *
 * @return {Array}
 * @api private
 */

Runner.prototype.parents = function(){
  var suite = this.suite
    , suites = [];
  while (suite = suite.parent) suites.push(suite);
  return suites;
};

/**
 * Run the current test and callback `fn(err)`.
 *
 * @param {Function} fn
 * @api private
 */

Runner.prototype.runTest = function(fn){
  var test = this.test
    , self = this;

  if (this.asyncOnly) test.asyncOnly = true;

  try {
    test.on('error', function(err){
      self.fail(test, err);
    });
    test.run(fn);
  } catch (err) {
    fn(err);
  }
};

/**
 * Run tests in the given `suite` and invoke
 * the callback `fn()` when complete.
 *
 * @param {Suite} suite
 * @param {Function} fn
 * @api private
 */

Runner.prototype.runTests = function(suite, fn){
  var self = this
    , tests = suite.tests.slice()
    , test;

  function next(err) {
    // if we bail after first err
    if (self.failures && suite._bail) return fn();

    // next test
    test = tests.shift();

    // all done
    if (!test) return fn();

    // grep
    var match = self._grep.test(test.fullTitle());
    if (self._invert) match = !match;
    if (!match) return next();

    // pending
    if (test.pending) {
      self.emit('pending', test);
      self.emit('test end', test);
      return next();
    }

    // execute test and hook(s)
    self.emit('test', self.test = test);
    self.hookDown('beforeEach', function(){
      self.currentRunnable = self.test;
      self.runTest(function(err){
        test = self.test;

        if (err) {
          self.fail(test, err);
          self.emit('test end', test);
          return self.hookUp('afterEach', next);
        }

        test.state = 'passed';
        self.emit('pass', test);
        self.emit('test end', test);
        self.hookUp('afterEach', next);
      });
    });
  }

  this.next = next;
  next();
};

/**
 * Run the given `suite` and invoke the
 * callback `fn()` when complete.
 *
 * @param {Suite} suite
 * @param {Function} fn
 * @api private
 */

Runner.prototype.runSuite = function(suite, fn){
  var total = this.grepTotal(suite)
    , self = this
    , i = 0;

  debug('run suite %s', suite.fullTitle());

  if (!total) return fn();

  this.emit('suite', this.suite = suite);

  function next() {
    var curr = suite.suites[i++];
    if (!curr) return done();
    self.runSuite(curr, next);
  }

  function done() {
    self.suite = suite;
    self.hook('afterAll', function(){
      self.emit('suite end', suite);
      fn();
    });
  }

  this.hook('beforeAll', function(){
    self.runTests(suite, next);
  });
};

/**
 * Handle uncaught exceptions.
 *
 * @param {Error} err
 * @api private
 */

Runner.prototype.uncaught = function(err){
  debug('uncaught exception %s', err.message);
  var runnable = this.currentRunnable;
  if (!runnable || 'failed' == runnable.state) return;
  runnable.clearTimeout();
  err.uncaught = true;
  this.fail(runnable, err);

  // recover from test
  if ('test' == runnable.type) {
    this.emit('test end', runnable);
    this.hookUp('afterEach', this.next);
    return;
  }

  // bail on hooks
  this.emit('end');
};

/**
 * Run the root suite and invoke `fn(failures)`
 * on completion.
 *
 * @param {Function} fn
 * @return {Runner} for chaining
 * @api public
 */

Runner.prototype.run = function(fn){
  var self = this
    , fn = fn || function(){};

  function uncaught(err){
    self.uncaught(err);
  }

  debug('start');

  // callback
  this.on('end', function(){
    debug('end');
    process.removeListener('uncaughtException', uncaught);
    fn(self.failures);
  });

  // run suites
  this.emit('start');
  this.runSuite(this.suite, function(){
    debug('finished running');
    self.emit('end');
  });

  // uncaught exception
  process.on('uncaughtException', uncaught);

  return this;
};

/**
 * Filter leaks with the given globals flagged as `ok`.
 *
 * @param {Array} ok
 * @param {Array} globals
 * @return {Array}
 * @api private
 */

function filterLeaks(ok, globals) {
  return filter(globals, function(key){
    // Firefox and Chrome exposes iframes as index inside the window object
    if (/^d+/.test(key)) return false;
    var matched = filter(ok, function(ok){
      if (~ok.indexOf('*')) return 0 == key.indexOf(ok.split('*')[0]);
      // Opera and IE expose global variables for HTML element IDs (issue #243)
      if (/^mocha-/.test(key)) return true;
      return key == ok;
    });
    return matched.length == 0 && (!global.navigator || 'onerror' !== key);
  });
}
<commit_msg>runner.js: 'pending' event is not mentioned in docs<commit_after>/**
 * Module dependencies.
 */

var EventEmitter = require('events').EventEmitter
  , debug = require('debug')('mocha:runner')
  , Test = require('./test')
  , utils = require('./utils')
  , filter = utils.filter
  , keys = utils.keys;

/**
 * Non-enumerable globals.
 */

var globals = [
  'setTimeout',
  'clearTimeout',
  'setInterval',
  'clearInterval',
  'XMLHttpRequest',
  'Date'
];

/**
 * Expose `Runner`.
 */

module.exports = Runner;

/**
 * Initialize a `Runner` for the given `suite`.
 *
 * Events:
 *
 *   - `start`  execution started
 *   - `end`  execution complete
 *   - `suite`  (suite) test suite execution started
 *   - `suite end`  (suite) all tests (and sub-suites) have finished
 *   - `test`  (test) test execution started
 *   - `test end`  (test) test completed
 *   - `hook`  (hook) hook execution started
 *   - `hook end`  (hook) hook complete
 *   - `pass`  (test) test passed
 *   - `fail`  (test, err) test failed
 *   - `pending`  (test) test pending
 *
 * @api public
 */

function Runner(suite) {
  var self = this;
  this._globals = [];
  this.suite = suite;
  this.total = suite.total();
  this.failures = 0;
  this.on('test end', function(test){ self.checkGlobals(test); });
  this.on('hook end', function(hook){ self.checkGlobals(hook); });
  this.grep(/.*/);
  this.globals(this.globalProps().concat(['errno']));
}

/**
 * Wrapper for setImmediate, process.nextTick, or browser polyfill.
 *
 * @param {Function} fn
 * @api private
 */

Runner.immediately = global.setImmediate || process.nextTick;

/**
 * Inherit from `EventEmitter.prototype`.
 */

Runner.prototype.__proto__ = EventEmitter.prototype;

/**
 * Run tests with full titles matching `re`. Updates runner.total
 * with number of tests matched.
 *
 * @param {RegExp} re
 * @param {Boolean} invert
 * @return {Runner} for chaining
 * @api public
 */

Runner.prototype.grep = function(re, invert){
  debug('grep %s', re);
  this._grep = re;
  this._invert = invert;
  this.total = this.grepTotal(this.suite);
  return this;
};

/**
 * Returns the number of tests matching the grep search for the
 * given suite.
 *
 * @param {Suite} suite
 * @return {Number}
 * @api public
 */

Runner.prototype.grepTotal = function(suite) {
  var self = this;
  var total = 0;

  suite.eachTest(function(test){
    var match = self._grep.test(test.fullTitle());
    if (self._invert) match = !match;
    if (match) total++;
  });

  return total;
};

/**
 * Return a list of global properties.
 *
 * @return {Array}
 * @api private
 */

Runner.prototype.globalProps = function() {
  var props = utils.keys(global);

  // non-enumerables
  for (var i = 0; i < globals.length; ++i) {
    if (~utils.indexOf(props, globals[i])) continue;
    props.push(globals[i]);
  }

  return props;
};

/**
 * Allow the given `arr` of globals.
 *
 * @param {Array} arr
 * @return {Runner} for chaining
 * @api public
 */

Runner.prototype.globals = function(arr){
  if (0 == arguments.length) return this._globals;
  debug('globals %j', arr);
  utils.forEach(arr, function(arr){
    this._globals.push(arr);
  }, this);
  return this;
};

/**
 * Check for global variable leaks.
 *
 * @api private
 */

Runner.prototype.checkGlobals = function(test){
  if (this.ignoreLeaks) return;
  var ok = this._globals;
  var globals = this.globalProps();
  var isNode = process.kill;
  var leaks;

  // check length - 2 ('errno' and 'location' globals)
  if (isNode && 1 == ok.length - globals.length) return
  else if (2 == ok.length - globals.length) return;

  leaks = filterLeaks(ok, globals);
  this._globals = this._globals.concat(leaks);

  if (leaks.length > 1) {
    this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + ''));
  } else if (leaks.length) {
    this.fail(test, new Error('global leak detected: ' + leaks[0]));
  }
};

/**
 * Fail the given `test`.
 *
 * @param {Test} test
 * @param {Error} err
 * @api private
 */

Runner.prototype.fail = function(test, err){
  ++this.failures;
  test.state = 'failed';

  if ('string' == typeof err) {
    err = new Error('the string "' + err + '" was thrown, throw an Error :)');
  }

  this.emit('fail', test, err);
};

/**
 * Fail the given `hook` with `err`.
 *
 * Hook failures (currently) hard-end due
 * to that fact that a failing hook will
 * surely cause subsequent tests to fail,
 * causing jumbled reporting.
 *
 * @param {Hook} hook
 * @param {Error} err
 * @api private
 */

Runner.prototype.failHook = function(hook, err){
  this.fail(hook, err);
  this.emit('end');
};

/**
 * Run hook `name` callbacks and then invoke `fn()`.
 *
 * @param {String} name
 * @param {Function} function
 * @api private
 */

Runner.prototype.hook = function(name, fn){
  var suite = this.suite
    , hooks = suite['_' + name]
    , self = this
    , timer;

  function next(i) {
    var hook = hooks[i];
    if (!hook) return fn();
    if (self.failures && suite.bail()) return fn();
    self.currentRunnable = hook;

    self.emit('hook', hook);

    hook.on('error', function(err){
      self.failHook(hook, err);
    });

    hook.run(function(err){
      hook.removeAllListeners('error');
      var testError = hook.error();
      if (testError) self.fail(self.test, testError);
      if (err) return self.failHook(hook, err);
      self.emit('hook end', hook);
      next(++i);
    });
  }

  Runner.immediately(function(){
    next(0);
  });
};

/**
 * Run hook `name` for the given array of `suites`
 * in order, and callback `fn(err)`.
 *
 * @param {String} name
 * @param {Array} suites
 * @param {Function} fn
 * @api private
 */

Runner.prototype.hooks = function(name, suites, fn){
  var self = this
    , orig = this.suite;

  function next(suite) {
    self.suite = suite;

    if (!suite) {
      self.suite = orig;
      return fn();
    }

    self.hook(name, function(err){
      if (err) {
        self.suite = orig;
        return fn(err);
      }

      next(suites.pop());
    });
  }

  next(suites.pop());
};

/**
 * Run hooks from the top level down.
 *
 * @param {String} name
 * @param {Function} fn
 * @api private
 */

Runner.prototype.hookUp = function(name, fn){
  var suites = [this.suite].concat(this.parents()).reverse();
  this.hooks(name, suites, fn);
};

/**
 * Run hooks from the bottom up.
 *
 * @param {String} name
 * @param {Function} fn
 * @api private
 */

Runner.prototype.hookDown = function(name, fn){
  var suites = [this.suite].concat(this.parents());
  this.hooks(name, suites, fn);
};

/**
 * Return an array of parent Suites from
 * closest to furthest.
 *
 * @return {Array}
 * @api private
 */

Runner.prototype.parents = function(){
  var suite = this.suite
    , suites = [];
  while (suite = suite.parent) suites.push(suite);
  return suites;
};

/**
 * Run the current test and callback `fn(err)`.
 *
 * @param {Function} fn
 * @api private
 */

Runner.prototype.runTest = function(fn){
  var test = this.test
    , self = this;

  if (this.asyncOnly) test.asyncOnly = true;

  try {
    test.on('error', function(err){
      self.fail(test, err);
    });
    test.run(fn);
  } catch (err) {
    fn(err);
  }
};

/**
 * Run tests in the given `suite` and invoke
 * the callback `fn()` when complete.
 *
 * @param {Suite} suite
 * @param {Function} fn
 * @api private
 */

Runner.prototype.runTests = function(suite, fn){
  var self = this
    , tests = suite.tests.slice()
    , test;

  function next(err) {
    // if we bail after first err
    if (self.failures && suite._bail) return fn();

    // next test
    test = tests.shift();

    // all done
    if (!test) return fn();

    // grep
    var match = self._grep.test(test.fullTitle());
    if (self._invert) match = !match;
    if (!match) return next();

    // pending
    if (test.pending) {
      self.emit('pending', test);
      self.emit('test end', test);
      return next();
    }

    // execute test and hook(s)
    self.emit('test', self.test = test);
    self.hookDown('beforeEach', function(){
      self.currentRunnable = self.test;
      self.runTest(function(err){
        test = self.test;

        if (err) {
          self.fail(test, err);
          self.emit('test end', test);
          return self.hookUp('afterEach', next);
        }

        test.state = 'passed';
        self.emit('pass', test);
        self.emit('test end', test);
        self.hookUp('afterEach', next);
      });
    });
  }

  this.next = next;
  next();
};

/**
 * Run the given `suite` and invoke the
 * callback `fn()` when complete.
 *
 * @param {Suite} suite
 * @param {Function} fn
 * @api private
 */

Runner.prototype.runSuite = function(suite, fn){
  var total = this.grepTotal(suite)
    , self = this
    , i = 0;

  debug('run suite %s', suite.fullTitle());

  if (!total) return fn();

  this.emit('suite', this.suite = suite);

  function next() {
    var curr = suite.suites[i++];
    if (!curr) return done();
    self.runSuite(curr, next);
  }

  function done() {
    self.suite = suite;
    self.hook('afterAll', function(){
      self.emit('suite end', suite);
      fn();
    });
  }

  this.hook('beforeAll', function(){
    self.runTests(suite, next);
  });
};

/**
 * Handle uncaught exceptions.
 *
 * @param {Error} err
 * @api private
 */

Runner.prototype.uncaught = function(err){
  debug('uncaught exception %s', err.message);
  var runnable = this.currentRunnable;
  if (!runnable || 'failed' == runnable.state) return;
  runnable.clearTimeout();
  err.uncaught = true;
  this.fail(runnable, err);

  // recover from test
  if ('test' == runnable.type) {
    this.emit('test end', runnable);
    this.hookUp('afterEach', this.next);
    return;
  }

  // bail on hooks
  this.emit('end');
};

/**
 * Run the root suite and invoke `fn(failures)`
 * on completion.
 *
 * @param {Function} fn
 * @return {Runner} for chaining
 * @api public
 */

Runner.prototype.run = function(fn){
  var self = this
    , fn = fn || function(){};

  function uncaught(err){
    self.uncaught(err);
  }

  debug('start');

  // callback
  this.on('end', function(){
    debug('end');
    process.removeListener('uncaughtException', uncaught);
    fn(self.failures);
  });

  // run suites
  this.emit('start');
  this.runSuite(this.suite, function(){
    debug('finished running');
    self.emit('end');
  });

  // uncaught exception
  process.on('uncaughtException', uncaught);

  return this;
};

/**
 * Filter leaks with the given globals flagged as `ok`.
 *
 * @param {Array} ok
 * @param {Array} globals
 * @return {Array}
 * @api private
 */

function filterLeaks(ok, globals) {
  return filter(globals, function(key){
    // Firefox and Chrome exposes iframes as index inside the window object
    if (/^d+/.test(key)) return false;
    var matched = filter(ok, function(ok){
      if (~ok.indexOf('*')) return 0 == key.indexOf(ok.split('*')[0]);
      // Opera and IE expose global variables for HTML element IDs (issue #243)
      if (/^mocha-/.test(key)) return true;
      return key == ok;
    });
    return matched.length == 0 && (!global.navigator || 'onerror' !== key);
  });
}
<|endoftext|>


<commit_before>import _ from 'lodash';
import path from 'path';
import crypto from 'crypto';
import fs from 'fs';
import Db from './db';
import Migration from './migration';
import { getMigrationTableSchema, finallyPromise } from './utils';

export { PgLiteral } from './utils';

const readdir = (...args) =>
  new Promise((resolve, reject) =>
    fs.readdir(
      ...args,
      (err, files) => (
        err
          ? reject(err)
          : resolve(files)
      )
    )
  );
const nameColumn = 'name';
const runOnColumn = 'run_on';

const loadMigrationFiles = (db, options) =>
  readdir(`${options.dir}/`)
    .then(files =>
      _.chain(files)
        .filter(file => file.match(/.+\.js$/g) !== null && file !== 'index.js')
        .map((file) => {
          const file_path = `${options.dir}/${file}`;
          // eslint-disable-next-line global-require,import/no-dynamic-require
          const actions = require(path.relative(__dirname, file_path));
          return new Migration(db, file_path, actions, options);
        })
        .sortBy('name')
        .value()
    )
    .catch((err) => {
      throw new Error(`Can't get migration files: ${err.stack}`);
    });

const lock = (db, options) => {
  const schema = getMigrationTableSchema(options);
  const lockName = crypto.randomBytes(30).toString('base64');
  const getCurrentLockName = () =>
    db
      .select(`SELECT obj_description(c.oid) as "comment"
                FROM pg_class c join pg_namespace n ON (c.relnamespace = n.oid)
                WHERE c.relname = '${options.migrations_table}' and c.relkind = 'r' and n.nspname = '${schema}'`)
      .then((rows) => {
        if (rows.length > 1) {
          throw new Error('More then one migration table');
        } else if (rows.length === 1) {
          return rows[0].comment;
        }
        return null;
      });

  return db.query('BEGIN')
    .then(() => db.query(`LOCK "${schema}"."${options.migrations_table}" IN ACCESS EXCLUSIVE MODE`))
    .then(getCurrentLockName)
    .then((currentLockName) => {
      if (currentLockName) {
        throw new Error('Another migration is already running');
      }
    })
    .then(() => db.query(`COMMENT ON TABLE "${schema}"."${options.migrations_table}" IS '${lockName}'`))
    .then(() => db.query('COMMIT'));
};

const unlock = (db, options) => {
  const schema = getMigrationTableSchema(options);
  return db.query(`COMMENT ON TABLE "${schema}"."${options.migrations_table}" IS NULL`);
};

const getRunMigrations = (db, options) => {
  const schema = getMigrationTableSchema(options);
  return db.select(`SELECT table_name FROM information_schema.tables WHERE table_schema = '${schema}' AND table_name = '${options.migrations_table}'`)
    .then(migrationTables =>
      (migrationTables && migrationTables.length === 1)
      || db.query(`CREATE TABLE "${schema}"."${options.migrations_table}" ( id SERIAL, ${nameColumn} varchar(255) NOT NULL, ${runOnColumn} timestamp NOT NULL)`)
    )
    .then(() =>
      lock(db, options)
    )
    .then(() =>
      db.addBeforeCloseListener(() => unlock(db, options))
    )
    .then(() =>
      db.column(`SELECT ${nameColumn} FROM "${schema}"."${options.migrations_table}" ORDER BY ${runOnColumn}`, nameColumn)
    )
    .catch((err) => {
      throw new Error(`Unable to fetch migrations: ${err.stack}`);
    });
};

const getMigrationsToRun = (options, runNames, migrations) => {
  if (options.direction === 'down') {
    const toRun = runNames
      .filter(migration_name => !options.file || options.file === migration_name)
      .map(migration_name =>
        migrations.find(({ name }) => name === migration_name) || migration_name
      )
      .slice(-Math.abs(options.count || 1))
      .reverse();
    const deletedMigrations = toRun.filter(migration => typeof migration === 'string');
    if (deletedMigrations.length) {
      throw new Error(`Definitions of migrations ${deletedMigrations.join(', ')} have been deleted.`);
    }
    return toRun;
  }
  return migrations
    .filter(({ name }) =>
      runNames.indexOf(name) < 0 && (!options.file || options.file === name)
    )
    .slice(0, Math.abs(options.count || Infinity));
};

export default (options) => {
  const db = Db(options.database_url);
  return Promise.resolve()
    .then(() => (
      options.schema
        ? db.query(`SET SCHEMA '${options.schema}'`)
        : null
    ))
    .then(() =>
      Promise
        .all([
          loadMigrationFiles(db, options),
          getRunMigrations(db, options),
        ])
    )
    .then(([migrations, runNames]) => {
      if (options.checkOrder) {
        const len = Math.min(runNames.length, migrations.length);
        for (let i = 0; i < len; i += 1) {
          if (runNames[i] !== migrations[i].name) {
            throw new Error(`Not run migration ${migrations[i].name} is preceding already run migration ${runNames[i]}`);
          }
        }
      }

      const toRun = getMigrationsToRun(options, runNames, migrations);

      if (!toRun.length) {
        console.log('No migrations to run!');
        return null;
      }

      // TODO: add some fancy colors to logging
      console.log('> Migrating files:');
      toRun.forEach((m) => {
        console.log(`> - ${m.name}`);
      });

      return toRun.reduce(
        (promise, migration) => promise.then(() => (
          options.direction === 'up'
            ? migration.applyUp()
            : migration.applyDown()
        )),
        Promise.resolve()
      );
    })
    .catch((e) => {
      console.log('> Rolling back attempted migration ...');
      return db.query('ROLLBACK')
        .then(...finallyPromise(() => {
          throw e;
        }));
    })
    .then(...finallyPromise(db.close));
};

export const unlockRunner = (options) => {
  const db = Db(options.database_url);
  return unlock(db, options)
    .then(...finallyPromise(db.close));
};
<commit_msg>Add support for TypeScript migrations (#93)<commit_after>import _ from 'lodash';
import path from 'path';
import crypto from 'crypto';
import fs from 'fs';
import Db from './db';
import Migration from './migration';
import { getMigrationTableSchema, finallyPromise } from './utils';

export { PgLiteral } from './utils';

const readdir = (...args) =>
  new Promise((resolve, reject) =>
    fs.readdir(
      ...args,
      (err, files) => (
        err
          ? reject(err)
          : resolve(files)
      )
    )
  );
const nameColumn = 'name';
const runOnColumn = 'run_on';

const loadMigrationFiles = (db, options) =>
  readdir(`${options.dir}/`)
    .then(files =>
      _.chain(files)
        .map((file) => {
          const file_path = `${options.dir}/${file}`;
          // eslint-disable-next-line global-require,import/no-dynamic-require
          const actions = require(path.relative(__dirname, file_path));
          return new Migration(db, file_path, actions, options);
        })
        .sortBy('name')
        .value()
    )
    .catch((err) => {
      throw new Error(`Can't get migration files: ${err.stack}`);
    });

const lock = (db, options) => {
  const schema = getMigrationTableSchema(options);
  const lockName = crypto.randomBytes(30).toString('base64');
  const getCurrentLockName = () =>
    db
      .select(`SELECT obj_description(c.oid) as "comment"
                FROM pg_class c join pg_namespace n ON (c.relnamespace = n.oid)
                WHERE c.relname = '${options.migrations_table}' and c.relkind = 'r' and n.nspname = '${schema}'`)
      .then((rows) => {
        if (rows.length > 1) {
          throw new Error('More then one migration table');
        } else if (rows.length === 1) {
          return rows[0].comment;
        }
        return null;
      });

  return db.query('BEGIN')
    .then(() => db.query(`LOCK "${schema}"."${options.migrations_table}" IN ACCESS EXCLUSIVE MODE`))
    .then(getCurrentLockName)
    .then((currentLockName) => {
      if (currentLockName) {
        throw new Error('Another migration is already running');
      }
    })
    .then(() => db.query(`COMMENT ON TABLE "${schema}"."${options.migrations_table}" IS '${lockName}'`))
    .then(() => db.query('COMMIT'));
};

const unlock = (db, options) => {
  const schema = getMigrationTableSchema(options);
  return db.query(`COMMENT ON TABLE "${schema}"."${options.migrations_table}" IS NULL`);
};

const getRunMigrations = (db, options) => {
  const schema = getMigrationTableSchema(options);
  return db.select(`SELECT table_name FROM information_schema.tables WHERE table_schema = '${schema}' AND table_name = '${options.migrations_table}'`)
    .then(migrationTables =>
      (migrationTables && migrationTables.length === 1)
      || db.query(`CREATE TABLE "${schema}"."${options.migrations_table}" ( id SERIAL, ${nameColumn} varchar(255) NOT NULL, ${runOnColumn} timestamp NOT NULL)`)
    )
    .then(() =>
      lock(db, options)
    )
    .then(() =>
      db.addBeforeCloseListener(() => unlock(db, options))
    )
    .then(() =>
      db.column(`SELECT ${nameColumn} FROM "${schema}"."${options.migrations_table}" ORDER BY ${runOnColumn}`, nameColumn)
    )
    .catch((err) => {
      throw new Error(`Unable to fetch migrations: ${err.stack}`);
    });
};

const getMigrationsToRun = (options, runNames, migrations) => {
  if (options.direction === 'down') {
    const toRun = runNames
      .filter(migration_name => !options.file || options.file === migration_name)
      .map(migration_name =>
        migrations.find(({ name }) => name === migration_name) || migration_name
      )
      .slice(-Math.abs(options.count || 1))
      .reverse();
    const deletedMigrations = toRun.filter(migration => typeof migration === 'string');
    if (deletedMigrations.length) {
      throw new Error(`Definitions of migrations ${deletedMigrations.join(', ')} have been deleted.`);
    }
    return toRun;
  }
  return migrations
    .filter(({ name }) =>
      runNames.indexOf(name) < 0 && (!options.file || options.file === name)
    )
    .slice(0, Math.abs(options.count || Infinity));
};

export default (options) => {
  const db = Db(options.database_url);
  return Promise.resolve()
    .then(() => (
      options.schema
        ? db.query(`SET SCHEMA '${options.schema}'`)
        : null
    ))
    .then(() =>
      Promise
        .all([
          loadMigrationFiles(db, options),
          getRunMigrations(db, options),
        ])
    )
    .then(([migrations, runNames]) => {
      if (options.checkOrder) {
        const len = Math.min(runNames.length, migrations.length);
        for (let i = 0; i < len; i += 1) {
          if (runNames[i] !== migrations[i].name) {
            throw new Error(`Not run migration ${migrations[i].name} is preceding already run migration ${runNames[i]}`);
          }
        }
      }

      const toRun = getMigrationsToRun(options, runNames, migrations);

      if (!toRun.length) {
        console.log('No migrations to run!');
        return null;
      }

      // TODO: add some fancy colors to logging
      console.log('> Migrating files:');
      toRun.forEach((m) => {
        console.log(`> - ${m.name}`);
      });

      return toRun.reduce(
        (promise, migration) => promise.then(() => (
          options.direction === 'up'
            ? migration.applyUp()
            : migration.applyDown()
        )),
        Promise.resolve()
      );
    })
    .catch((e) => {
      console.log('> Rolling back attempted migration ...');
      return db.query('ROLLBACK')
        .then(...finallyPromise(() => {
          throw e;
        }));
    })
    .then(...finallyPromise(db.close));
};

export const unlockRunner = (options) => {
  const db = Db(options.database_url);
  return unlock(db, options)
    .then(...finallyPromise(db.close));
};
<|endoftext|>


<commit_before>on('pull_request.closed')
  .filter(context => context.payload.pull_request.merged)
  .filter(
    context =>
      context.payload.pull_request.head.ref.slice(0, 11) !== 'dependabot/'
  )
  .filter(context => context.payload.pull_request.base.ref === 'master')
  .comment(`This pull request was merged to [{{ pull_request.base.ref }}]({{ repository.html_url }}/tree/{{ pull_request.base.ref }}) branch. Now this change is waiting for deployment.
Deploys usually happen every few weeks. After deployment changes are copied to [gh-pages]({{ repository.html_url }}/tree/gh-pages) branch.

This badge displays deployment status:
![](https://img.shields.io/github/commit-status/{{ repository.full_name }}/gh-pages/{{ pull_request.merge_commit_sha }}.svg?label=deploy%20status)`)
<commit_msg>Improved deployment bot message (#1996)<commit_after>on('pull_request.closed')
  .filter(context => context.payload.pull_request.merged)
  .filter(
    context =>
      context.payload.pull_request.head.ref.slice(0, 11) !== 'dependabot/'
  )
  .filter(context => context.payload.pull_request.base.ref === 'master')
  .comment(`This pull request was merged to [{{ pull_request.base.ref }}]({{ repository.html_url }}/tree/{{ pull_request.base.ref }}) branch. This change is now waiting for deployment, which will usually happen within a few days. Stay tuned by joining our #ops channel on [Discord](https://discordapp.com/invite/HjJCwm5)!

After deployment changes are copied to [gh-pages]({{ repository.html_url }}/tree/gh-pages) branch.

This badge displays deployment status:
![](https://img.shields.io/github/commit-status/{{ repository.full_name }}/gh-pages/{{ pull_request.merge_commit_sha }}.svg?label=deploy%20status)`)
<|endoftext|>


<commit_before>// PR commentary for Authelia branch based contributions
on('pull_request.opened')
    .filter(
        context =>
            context.payload.pull_request.head.label.slice(0, 9) === 'authelia:'
    )
    .filter(
        context =>
            context.payload.pull_request.head.ref.slice(0, 11) !== 'dependabot/'
    )
    .comment(`## Artifacts
These changes are published for testing on Buildkite and DockerHub.

### Docker Container
* \`docker pull authelia/authelia:{{ pull_request.head.ref }}\``)

// PR commentary for third party based contributions
on('pull_request.opened')
    .filter(
        context =>
            context.payload.pull_request.head.label.slice(0, 9) !== 'authelia:'
    )
    .filter(
        context =>
            !context.payload.pull_request.head.label.includes(':master')
    )
    .comment(`Thanks for choosing to contribute. We lint all PR's with golangci-lint, I may add a review to your PR with some suggestions.

You are free to apply the changes if you're comfortable, alternatively you are welcome to ask a team member for advice.

## Artifacts
These changes once approved by a team member will be published for testing on Buildkite and DockerHub.

### Docker Container
* \`docker pull authelia/authelia:PR{{ pull_request.number }}\``)

// PR commentary for forked master branches
on('pull_request.opened')
    .filter(
        context =>
            context.payload.pull_request.head.label.slice(0, 9) !== 'authelia:'
    )
    .filter(
        context =>
            context.payload.pull_request.head.label.includes(':master')
    )
    .comment(`Thanks for choosing to contribute. It appears that you're submitting a PR from a forked master branch.

This causes issues with codecov, please close this PR and re-submit your PR from a branch other than master.`)<commit_msg>[CI] Final touches to PR commentary (#1171)<commit_after>// PR commentary for Authelia branch based contributions
on('pull_request.opened')
    .filter(
        context =>
            context.payload.pull_request.head.label.slice(0, 9) === 'authelia:'
    )
    .filter(
        context =>
            context.payload.pull_request.head.ref.slice(0, 11) !== 'dependabot/'
    )
    .comment(`## Artifacts
These changes are published for testing on Buildkite and DockerHub.

### Docker Container
* \`docker pull authelia/authelia:{{ pull_request.head.ref }}\``)

// PR commentary for third party based contributions
on('pull_request.opened')
    .filter(
        context =>
            context.payload.pull_request.head.label.slice(0, 9) !== 'authelia:'
    )
    .filter(
        context =>
            !context.payload.pull_request.head.label.includes(':master')
    )
    .comment(`Thanks for choosing to contribute @{{ user.login }}. We lint all PR's with golangci-lint, I may add a review to your PR with some suggestions.

You are free to apply the changes if you're comfortable, alternatively you are welcome to ask a team member for advice.

## Artifacts
These changes once approved by a team member will be published for testing on Buildkite and DockerHub.

### Docker Container
* \`docker pull authelia/authelia:PR{{ pull_request.number }}\``)

// PR commentary for forked master branches
on('pull_request.opened')
    .filter(
        context =>
            context.payload.pull_request.head.label.slice(0, 9) !== 'authelia:'
    )
    .filter(
        context =>
            context.payload.pull_request.head.label.includes(':master')
    )
    .comment(`Thanks for choosing to contribute @{{ user.login }}.

Unfortunately it appears that you're submitting a PR from a forked master branch and this is known to causes issues with codecov. Please re-submit your PR from a branch other than master.`)
    .close()<|endoftext|>


<commit_before>var yaml = require('js-yaml'),
_ = require('lodash');

var tags = [
  { short: 'Include', full: 'Fn::Include', type: 'scalar' },
  { short: 'Include', full: 'Fn::Include', type: 'mapping' },
  { short: 'Stringify', full: 'Fn::Stringify', type: 'sequence' },
  { short: 'Stringify', full: 'Fn::Stringify', type: 'mapping' },
  { short: 'Map', full: 'Fn::Map', type: 'sequence' },
  { short: 'Flatten', full: 'Fn::Flatten', type: 'sequence' },
  { short: 'Merge', full: 'Fn::Merge', type: 'sequence' },
  // http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html
  { short: 'Base64', full: 'Fn::Base64', type: 'scalar' },
  { short: 'Base64', full: 'Fn::Base64', type: 'mapping' },
  { short: 'FindInMap', full: 'Fn::FindInMap', type: 'sequence' },
  { short: 'GetAtt', full: 'Fn::GetAtt', type: 'sequence' },
  { short: 'GetAtt', full: 'Fn::GetAtt', type: 'scalar', dotSyntax: true },
  { short: 'GetAZs', full: 'Fn::GetAZs', type: 'sequence' },
  { short: 'ImportValue', full: 'Fn::ImportValue', type: 'scalar' },
  { short: 'ImportValue', full: 'Fn::ImportValue', type: 'mapping' },
  { short: 'Join', full: 'Fn::Join', type: 'sequence' },
  { short: 'Select', full: 'Fn::Select', type: 'sequence' },
  { short: 'Sub', full: 'Fn::Sub', type: 'sequence' },
  { short: 'Sub', full: 'Fn::Sub', type: 'mapping' },
  { short: 'Sub', full: 'Fn::Sub', type: 'scalar' },
  { short: 'Split', full: 'Fn::Split', type: 'sequence' },
  { short: 'Ref', full: 'Ref', type: 'scalar' },
  // http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/continuous-delivery-codepipeline-action-reference.html
  { short: 'GetParam', full: 'Fn::GetParam', type: 'sequence' },
  // http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-conditions.html
  { short: 'And', full: 'Fn::And', type: 'sequence' },
  { short: 'Equals', full: 'Fn::Equals', type: 'sequence' },
  { short: 'If', full: 'Fn::If', type: 'sequence' },
  { short: 'Not', full: 'Fn::Not', type: 'sequence' },
  { short: 'Or', full: 'Fn::Or', type: 'sequence' },
  { short: 'GetCidr', full: 'Fn::GetCidr', type: 'sequence' },
  { short: 'GetCidr', full: 'Fn::GetCidr', type: 'mapping' },

].map(function(fn) {
  return new yaml.Type('!' + fn.short, {
    kind: fn.type,
    construct: function(obj) {
      if(fn.dotSyntax && _.isString(obj)) {
        var indexOfDot = obj.indexOf('.');
        if(indexOfDot != -1)
          obj = [obj.substr(0, indexOfDot), obj.substr(indexOfDot + 1)];
        else obj = [obj];
      }
      return _.fromPairs([[fn.full, obj]]);
    }
  });
});

module.exports = yaml.Schema.create(tags);
<commit_msg>AWS decided to rename Fn::GetCidr to Fn::Cidr ...<commit_after>var yaml = require('js-yaml'),
_ = require('lodash');

var tags = [
  { short: 'Include', full: 'Fn::Include', type: 'scalar' },
  { short: 'Include', full: 'Fn::Include', type: 'mapping' },
  { short: 'Stringify', full: 'Fn::Stringify', type: 'sequence' },
  { short: 'Stringify', full: 'Fn::Stringify', type: 'mapping' },
  { short: 'Map', full: 'Fn::Map', type: 'sequence' },
  { short: 'Flatten', full: 'Fn::Flatten', type: 'sequence' },
  { short: 'Merge', full: 'Fn::Merge', type: 'sequence' },
  // http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html
  { short: 'Base64', full: 'Fn::Base64', type: 'scalar' },
  { short: 'Base64', full: 'Fn::Base64', type: 'mapping' },
  { short: 'FindInMap', full: 'Fn::FindInMap', type: 'sequence' },
  { short: 'GetAtt', full: 'Fn::GetAtt', type: 'sequence' },
  { short: 'GetAtt', full: 'Fn::GetAtt', type: 'scalar', dotSyntax: true },
  { short: 'GetAZs', full: 'Fn::GetAZs', type: 'sequence' },
  { short: 'ImportValue', full: 'Fn::ImportValue', type: 'scalar' },
  { short: 'ImportValue', full: 'Fn::ImportValue', type: 'mapping' },
  { short: 'Join', full: 'Fn::Join', type: 'sequence' },
  { short: 'Select', full: 'Fn::Select', type: 'sequence' },
  { short: 'Sub', full: 'Fn::Sub', type: 'sequence' },
  { short: 'Sub', full: 'Fn::Sub', type: 'mapping' },
  { short: 'Sub', full: 'Fn::Sub', type: 'scalar' },
  { short: 'Split', full: 'Fn::Split', type: 'sequence' },
  { short: 'Ref', full: 'Ref', type: 'scalar' },
  { short: 'Cidr', full: 'Fn::GetCidr', type: 'sequence' },
  { short: 'Cidr', full: 'Fn::GetCidr', type: 'mapping' },
  // http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/continuous-delivery-codepipeline-action-reference.html
  { short: 'GetParam', full: 'Fn::GetParam', type: 'sequence' },
  // http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-conditions.html
  { short: 'And', full: 'Fn::And', type: 'sequence' },
  { short: 'Equals', full: 'Fn::Equals', type: 'sequence' },
  { short: 'If', full: 'Fn::If', type: 'sequence' },
  { short: 'Not', full: 'Fn::Not', type: 'sequence' },
  { short: 'Or', full: 'Fn::Or', type: 'sequence' },

].map(function(fn) {
  return new yaml.Type('!' + fn.short, {
    kind: fn.type,
    construct: function(obj) {
      if(fn.dotSyntax && _.isString(obj)) {
        var indexOfDot = obj.indexOf('.');
        if(indexOfDot != -1)
          obj = [obj.substr(0, indexOfDot), obj.substr(indexOfDot + 1)];
        else obj = [obj];
      }
      return _.fromPairs([[fn.full, obj]]);
    }
  });
});

module.exports = yaml.Schema.create(tags);
<|endoftext|>