<commit_before>var YAML = require('js-yaml'),
    Importer = require('../importers/index');

function Exporter() {
  this.data = null;
  this.project = null;
}
Exporter.prototype = {
  get Data(){
    return this.data;
  }
};

Exporter.prototype.loadSLData = function (rawData, cb) {
  var importer = Importer.factory({
    name: 'StopLight',
    className: 'StopLight'
  });
  var me = this;
  importer.loadData(rawData)
  .then(function(){
    me.project = importer.import();
    cb();
  })
  .catch(function(err){
    cb(err);
  });
};

Exporter.prototype.loadProject = function (project) {
  this.project = project;
};

Exporter.prototype._export = function () {
  throw new Error('_export method not implemented');
};

Exporter.prototype.export = function (format) {
  var me = this;
  return new Promise(function(resolve, reject){
    try {
      me._export();

      var formattedData, exportedData = me._getData(format);
      resolve(exportedData);
      // if (typeof exportedData === 'object') {
      //   formattedData = JSON.stringify(exportedData);
      // } else {
      //   formattedData = exportedData;
      // }
      //
      // var importer = Importer.factory({
      //   name: 'AUTO',
      //   className: 'Auto'
      // });
      // importer.loadData(formattedData)
      // .then(function(){
      //   try {
      //     importer.import();
      //     resolve(exportedData);
      //   } catch(err) {
      //     resolve(exportedData, err);
      //   }
      // })
      // .catch(function(err){
      //   resolve(exportedData, err);
      // });
    } catch(err) {
      reject(err, null);
    }
  });
};

Exporter.prototype._getData = function(format) {
  switch (format) {
    case 'yaml':
      return YAML.dump(JSON.parse(JSON.stringify(this.Data)), {lineWidth: -1});
    default:
      return this.Data;
  }
};

Exporter.prototype._mapEndpoint = function () {
  throw new Error('_mapEndpoint method not implemented');
};

Exporter.prototype._mapSchema = function () {
  throw new Error('_mapSchema method not implemented');
};
Exporter.prototype._mapQueryString = function () {
  throw new Error('_mapQueryString method not implemented');
};
Exporter.prototype._mapURIParams = function () {
  throw new Error('_mapURIParams method not implemented');
};
Exporter.prototype._mapRequestBody = function () {
  throw new Error('_mapRequestBody method not implemented');
};
Exporter.prototype._mapResponseBody = function () {
  throw new Error('_mapResponseBody method not implemented');
};
Exporter.prototype._mapRequestHeaders = function () {
  throw new Error('_mapRequestHeaders method not implemented');
};

module.exports = Exporter;
<commit_msg>uncomment code my mistake<commit_after>var YAML = require('js-yaml'),
    Importer = require('../importers/index');

function Exporter() {
  this.data = null;
  this.project = null;
}
Exporter.prototype = {
  get Data(){
    return this.data;
  }
};

Exporter.prototype.loadSLData = function (rawData, cb) {
  var importer = Importer.factory({
    name: 'StopLight',
    className: 'StopLight'
  });
  var me = this;
  importer.loadData(rawData)
  .then(function(){
    me.project = importer.import();
    cb();
  })
  .catch(function(err){
    cb(err);
  });
};

Exporter.prototype.loadProject = function (project) {
  this.project = project;
};

Exporter.prototype._export = function () {
  throw new Error('_export method not implemented');
};

Exporter.prototype.export = function (format) {
  var me = this;
  return new Promise(function(resolve, reject){
    try {
      me._export();

      var formattedData, exportedData = me._getData(format);
      if (typeof exportedData === 'object') {
        formattedData = JSON.stringify(exportedData);
      } else {
        formattedData = exportedData;
      }

      var importer = Importer.factory({
        name: 'AUTO',
        className: 'Auto'
      });
      importer.loadData(formattedData)
          .then(function(){
            try {
              importer.import();
              resolve(exportedData);
            } catch(err) {
              resolve(exportedData, err);
            }
          })
          .catch(function(err){
            resolve(exportedData, err);
          });
    } catch(err) {
      reject(err, null);
    }
  });
};

Exporter.prototype._getData = function(format) {
  switch (format) {
    case 'yaml':
      return YAML.dump(JSON.parse(JSON.stringify(this.Data)), {lineWidth: -1});
    default:
      return this.Data;
  }
};

Exporter.prototype._mapEndpoint = function () {
  throw new Error('_mapEndpoint method not implemented');
};

Exporter.prototype._mapSchema = function () {
  throw new Error('_mapSchema method not implemented');
};
Exporter.prototype._mapQueryString = function () {
  throw new Error('_mapQueryString method not implemented');
};
Exporter.prototype._mapURIParams = function () {
  throw new Error('_mapURIParams method not implemented');
};
Exporter.prototype._mapRequestBody = function () {
  throw new Error('_mapRequestBody method not implemented');
};
Exporter.prototype._mapResponseBody = function () {
  throw new Error('_mapResponseBody method not implemented');
};
Exporter.prototype._mapRequestHeaders = function () {
  throw new Error('_mapRequestHeaders method not implemented');
};

module.exports = Exporter;
<|endoftext|>


<commit_before>(function() {
  var Player, Universe, constants, powerup, util;
  var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
  Player = require('player');
  powerup = require('powerup');
  util = require('util');
  constants = require('constants');
  module.exports = Universe = (function() {
    function Universe(id, name, colors) {
      this.player_map = {};
      this.powerup_map = {};
      this.tick_count = 0;
      this.stopped = true;
      this.is_touching = false;
      this.board = document.getElementById("universe");
      this.context = this.board.getContext("2d");
      this.createSelf(id, name, colors);
      this.connect();
    }
    Universe.prototype.startGame = function() {
      this.stopped = false;
      this.player_map[this.self.id] = this.self;
      this.enableControls();
      return this.gameTick();
    };
    Universe.prototype.stopGame = function() {
      this.stopped = true;
      this.tick_count = 0;
      return this.player_map = {};
    };
    Universe.prototype.createSelf = function(id, name, colors) {
      console.log("create self with id " + id);
      if (!name) {
        name = prompt("What is your dragon's name?");
        name = name.substr(0, 16);
      }
      return this.self = new Player({
        id: id,
        name: name,
        body_color: colors[4] || util.randomColor(),
        highlight_color: colors[2] || util.randomColor(),
        x: this.board.width / 2,
        y: this.board.height / 2
      });
    };
    Universe.prototype.gameTick = function() {
      var diff, id, player, start, _ref;
      if (this.stopped) {
        return;
      }
      start = (new Date()).getTime();
      this.tick_count++;
      this.board.width = this.board.width;
      _ref = this.players();
      for (id in _ref) {
        player = _ref[id];
        this.tickPlayer(player);
      }
      this.checkDeath();
      this.drawPowerups();
      this.drawOverlay();
      this.syncSelf();
      diff = Math.max(0, (new Date()).getTime() - start);
      return setTimeout((__bind(function() {
        return this.gameTick();
      }, this)), 40 - diff);
    };
    Universe.prototype.tickPlayer = function(player) {
      var id, powerup, target, _ref, _ref2;
      if (player.x <= 0 || player.x >= this.board.width) {
        player.angle = 2 * Math.PI - player.angle;
      } else if (player.y >= this.board.height || player.y <= 0) {
        player.angle = Math.PI - player.angle;
      }
      _ref = this.powerups;
      for (id in _ref) {
        powerup = _ref[id];
        if (powerup.contains(player)) {
          powerup.apply_bonus(player);
          this.removePowerup(id);
          if (player.id === this.self.id) {
            this.sendAction("removePowerup", id);
          }
        }
      }
      player.gameTick();
      _ref2 = this.players();
      for (id in _ref2) {
        target = _ref2[id];
        player.tryToBreath(target);
      }
      player.draw(this.context);
      return player.drawName(this.context, player !== this.self);
    };
    Universe.prototype.players = function() {
      var id, player, _ref, _results;
      _ref = this.player_map;
      _results = [];
      for (id in _ref) {
        player = _ref[id];
        _results.push(player);
      }
      return _results;
    };
    Universe.prototype.getPlayer = function(id) {
      return this.player_map[id];
    };
    Universe.prototype.removePlayer = function(id) {
      console.log("remove player " + id);
      return delete this.player_map[id];
    };
    Universe.prototype.addPlayer = function(state) {
      var player;
      console.log("add player " + state.id, state);
      player = new Player(state);
      this.player_map[player.id] = player;
      return player;
    };
    Universe.prototype.addPlayers = function(new_players) {
      var player, _i, _len, _results;
      _results = [];
      for (_i = 0, _len = new_players.length; _i < _len; _i++) {
        player = new_players[_i];
        _results.push(this.addPlayer(player));
      }
      return _results;
    };
    Universe.prototype.syncPlayer = function(state) {
      var k, player, v, _results;
      player = this.getPlayer(state.id);
      if (!player || player.id === this.self.id) {
        return;
      }
      _results = [];
      for (k in state) {
        v = state[k];
        _results.push(player[k] = v);
      }
      return _results;
    };
    Universe.prototype.powerups = function() {
      var id, powerup, _len, _ref, _results;
      _ref = this.powerup_map;
      _results = [];
      for (powerup = 0, _len = _ref.length; powerup < _len; powerup++) {
        id = _ref[powerup];
        _results.push(powerup);
      }
      return _results;
    };
    Universe.prototype.removePowerup = function(id) {
      return delete this.powerups[id];
    };
    Universe.prototype.addPowerup = function(opts) {
      console.log("add powerup");
      return this.powerups[opts.id] = powerup.createPowerup(opts.type, opts);
    };
    Universe.prototype.addPowerups = function(new_powerups) {
      var opts, _i, _len, _results;
      _results = [];
      for (_i = 0, _len = new_powerups.length; _i < _len; _i++) {
        opts = new_powerups[_i];
        _results.push(this.addPowerup(opts));
      }
      return _results;
    };
    Universe.prototype.syncScore = function(data) {
      var player;
      player = this.getPlayer(data.id);
      return player.kills = data.score;
    };
    Universe.prototype.drawOverlay = function() {
      this.context.font = "bold 10px sans-serif";
      this.context.fillStyle = "#fff";
      this.context.fillText(this.self.name, 10, 16);
      this.drawEnergyMeter();
      this.drawHealthMeter();
      return this.drawPlayerList();
    };
    Universe.prototype.drawPowerups = function() {
      var id, powerup, _ref, _results;
      _ref = this.powerups;
      _results = [];
      for (id in _ref) {
        powerup = _ref[id];
        _results.push(powerup.draw(this.context));
      }
      return _results;
    };
    Universe.prototype.drawPlayerList = function() {
      var player, players, x, y, _i, _len, _ref, _results;
      _ref = [this.board.width - 100, 15], x = _ref[0], y = _ref[1];
      this.context.fillStyle = "#fff";
      players = this.players().sort(function(a, b) {
        return b.kills - a.kills;
      });
      this.context.font = "bold 11px sans-serif";
      this.context.fillText("Current Scores", x, y);
      this.context.font = "11px sans-serif";
      _results = [];
      for (_i = 0, _len = players.length; _i < _len; _i++) {
        player = players[_i];
        y += 12;
        _results.push(this.context.fillText("" + (parseInt(player.kills)) + " " + player.name, x, y));
      }
      return _results;
    };
    Universe.prototype.drawStats = function() {
      var toTargAngle, totarget;
      this.context.fillStyle = "#fff";
      this.context.fillText("x: " + (parseInt(this.self.x)), 10, 10);
      this.context.fillText("y: " + (parseInt(this.self.y)), 10, 20);
      this.context.fillText("angle: " + this.self.angle, 10, 30);
      this.context.fillText("speed: " + this.self.speed, 10, 40);
      this.context.fillText("thrust: " + this.self.energy, 10, 50);
      this.context.fillText("id: " + this.self.id, 10, 60);
      this.context.fillText("dead: " + this.self.dead, 10, 70);
      this.context.fillText("pressn: " + (this.self.controls.anyPressed()), 10, 80);
      if (this.self.controls.target) {
        this.context.fillText("targetx: " + this.self.controls.target.x, 10, 90);
        this.context.fillText("targetx: " + this.self.controls.target.y, 10, 100);
      } else {
        this.context.fillText("No touch target!", 10, 90);
        this.context.fillText("", 10, 100);
      }
      totarget = util.subtractVec(this.self.controls.target, this.self);
      toTargAngle = Math.PI + Math.atan2(totarget.x, totarget.y);
      this.context.fillText("Target angle: " + toTargAngle, 10, 110);
      this.context.fillText("ToTarget vectorx: " + totarget.x, 10, 120);
      this.context.fillText("ToTarget vectory: " + totarget.y, 10, 130);
      this.context.fillText("DistToTarget: " + util.distanceFrom(this.self, this.self.controls.target), 10, 140);
      return this.context.fillText("Want to turn: " + (toTargAngle - this.self.angle), 10, 150);
    };
    Universe.prototype.disableControls = function() {
      this.board.removeEventListener("mousedown");
      document.removeEventListener("keyup");
      return document.removeEventListener("keydown");
    };
    Universe.prototype.enableControls = function() {
      this.board.addEventListener("mousedown", __bind(function(e) {
        if (!(e.target === this.board && !this.self.controls.anyPressed())) {
          return;
        }
        this.self.controls.target = {
          x: e.clientX - this.board.offsetLeft,
          y: e.clientY - this.board.offsetTop
        };
        this.self.controls.mousedown = true;
        return this.is_touching = true;
      }, this), false);
      this.board.addEventListener("mousemove", __bind(function(e) {
        if (!(this.is_touching || (!this.self.controls.anyPressed() && this.self.controls.mouseDown))) {
          return;
        }
        return this.self.controls.target = {
          x: e.clientX - this.board.offsetLeft,
          y: e.clientY - this.board.offsetTop
        };
      }, this), false);
      this.board.addEventListener("mouseup", __bind(function(e) {
        this.self.controls.mouseDown = false;
        if (!this.is_touching) {
          return;
        }
        return this.is_touching = false;
      }, this), false);
      document.addEventListener("keyup", __bind(function(e) {
        switch (e.keyCode) {
          case 87:
          case 73:
            this.self.controls.wPressed = false;
            break;
          case 68:
          case 76:
            this.self.controls.dPressed = false;
            break;
          case 65:
          case 74:
            this.self.controls.aPressed = false;
            break;
          case 32:
            this.self.controls.spacePressed = false;
            break;
          case 83:
          case 75:
            this.self.controls.sPressed = false;
        }
        return this.syncSelf();
      }, this), false);
      return document.addEventListener("keydown", __bind(function(e) {
        this.self.controls.target = false;
        switch (e.keyCode) {
          case 87:
          case 73:
            this.self.controls.wPressed = true;
            break;
          case 68:
          case 76:
            this.self.controls.dPressed = true;
            break;
          case 65:
          case 74:
            this.self.controls.aPressed = true;
            break;
          case 32:
            this.self.controls.spacePressed = true;
            e.preventDefault();
            break;
          case 83:
          case 75:
            this.self.controls.sPressed = true;
        }
        return this.syncSelf();
      }, this), false);
    };
    Universe.prototype.syncSelf = function() {
      return this.sendAction("syncSelf", this.self.serialized());
    };
    Universe.prototype.connect = function() {
      this.socket = new io.Socket(window.location.hostname);
      this.socket.on('connect', __bind(function() {
        this.sendAction("initSelf", this.self.serialized(true));
        return this.startGame();
      }, this));
      this.socket.on('disconnect', __bind(function() {
        return this.stopGame();
      }, this));
      this.socket.on('message', __bind(function(msg) {
        var req;
        req = JSON.parse(msg);
        return this[req.action](req.data);
      }, this));
      return this.socket.connect();
    };
    Universe.prototype.drawEnergyMeter = function() {
      var width, x, y, _ref;
      _ref = [10, 35], x = _ref[0], y = _ref[1];
      this.context.fillStyle = "rgba(255,255,255,0.2)";
      this.context.fillRect(x, y, 110, 11);
      this.context.fillStyle = "yellow";
      width = 110 * (this.self.energy / constants.maxEnergy);
      this.context.fillRect(x, y, width, 11);
      this.context.fillStyle = "rgba(0,0,0,0.5)";
      this.context.font = "9px sans-serif";
      return this.context.fillText("Energy", x + 2, y + 9);
    };
    Universe.prototype.drawHealthMeter = function() {
      var percent, x, y, _ref;
      _ref = [10, 20], x = _ref[0], y = _ref[1];
      this.context.fillStyle = "rgba(255,255,255,0.2)";
      this.context.fillRect(x, y, 110, 11);
      percent = this.self.hpPercent();
      this.context.fillStyle = percent > .2 ? "green" : "red";
      this.context.fillRect(x, y, percent * 110, 11);
      this.context.fillStyle = "rgba(0,0,0,0.5)";
      this.context.font = "9px sans-serif";
      return this.context.fillText("HP", x + 2, y + 9);
    };
    Universe.prototype.sendAction = function(action, data) {
      return this.socket.send({
        source: this.self.id,
        action: action,
        data: data
      });
    };
    Universe.prototype.checkDeath = function() {
      if (this.self.damage > constants.deadlyDamage || this.self.dead) {
        if (this.self.dead === 0) {
          console.log("" + this.self.name + " died at tick " + this.tick_count);
          this.sendAction("scorePoint", this.self.last_attacker);
          return this.self.dead = 1;
        } else if (this.self.dead >= constants.deathAnimationTime) {
          this.self.damage = 0;
          this.self.dead = 0;
          this.self.x = Math.random() * constants.universeWidth;
          this.self.y = Math.random() * constants.universeHeight;
          this.self.flash = 1;
          return this.self.energy = constants.maxEnergy;
        }
      }
    };
    return Universe;
  })();
}).call(this);
<commit_msg>coffeescript<commit_after>(function() {
  var Player, Universe, constants, powerup, util;
  var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
  Player = require('player');
  powerup = require('powerup');
  util = require('util');
  constants = require('constants');
  module.exports = Universe = (function() {
    function Universe(id, name, colors) {
      this.player_map = {};
      this.powerup_map = {};
      this.tick_count = 0;
      this.stopped = true;
      this.is_touching = false;
      this.board = document.getElementById("universe");
      this.context = this.board.getContext("2d");
      this.createSelf(id, name, colors);
      this.connect();
    }
    Universe.prototype.startGame = function() {
      this.stopped = false;
      this.player_map[this.self.id] = this.self;
      this.enableControls();
      return this.gameTick();
    };
    Universe.prototype.stopGame = function() {
      this.stopped = true;
      this.tick_count = 0;
      return this.player_map = {};
    };
    Universe.prototype.createSelf = function(id, name, colors) {
      console.log("create self with id " + id);
      if (!name) {
        name = prompt("What is your dragon's name?");
        name = name.substr(0, 16);
      }
      return this.self = new Player({
        id: id,
        name: name,
        body_color: colors[4] || util.randomColor(),
        highlight_color: colors[2] || util.randomColor(),
        x: this.board.width / 2,
        y: this.board.height / 2
      });
    };
    Universe.prototype.gameTick = function() {
      var diff, id, player, start, _ref;
      if (this.stopped) {
        return;
      }
      start = (new Date()).getTime();
      this.tick_count++;
      this.board.width = this.board.width;
      _ref = this.players();
      for (id in _ref) {
        player = _ref[id];
        this.tickPlayer(player);
      }
      this.checkDeath();
      this.drawPowerups();
      this.drawOverlay();
      this.syncSelf();
      diff = Math.max(0, (new Date()).getTime() - start);
      return setTimeout((__bind(function() {
        return this.gameTick();
      }, this)), 40 - diff);
    };
    Universe.prototype.tickPlayer = function(player) {
      var id, powerup, target, _ref, _ref2;
      if (player.x <= 0 || player.x >= this.board.width) {
        player.angle = 2 * Math.PI - player.angle;
      } else if (player.y >= this.board.height || player.y <= 0) {
        player.angle = Math.PI - player.angle;
      }
      _ref = this.powerups;
      for (id in _ref) {
        powerup = _ref[id];
        if (powerup.contains(player)) {
          powerup.apply_bonus(player);
          this.removePowerup(id);
          if (player.id === this.self.id) {
            this.sendAction("removePowerup", id);
          }
        }
      }
      player.gameTick();
      _ref2 = this.players();
      for (id in _ref2) {
        target = _ref2[id];
        player.tryToBreath(target);
      }
      player.draw(this.context);
      return player.drawName(this.context, player !== this.self);
    };
    Universe.prototype.players = function() {
      var id, player, _ref, _results;
      _ref = this.player_map;
      _results = [];
      for (id in _ref) {
        player = _ref[id];
        _results.push(player);
      }
      return _results;
    };
    Universe.prototype.getPlayer = function(id) {
      return this.player_map[id];
    };
    Universe.prototype.removePlayer = function(id) {
      console.log("remove player " + id);
      return delete this.player_map[id];
    };
    Universe.prototype.addPlayer = function(state) {
      var player;
      console.log("add player " + state.id, state);
      player = new Player(state);
      this.player_map[player.id] = player;
      return player;
    };
    Universe.prototype.addPlayers = function(new_players) {
      var player, _i, _len, _results;
      _results = [];
      for (_i = 0, _len = new_players.length; _i < _len; _i++) {
        player = new_players[_i];
        _results.push(this.addPlayer(player));
      }
      return _results;
    };
    Universe.prototype.syncPlayer = function(state) {
      var k, player, v, _results;
      player = this.getPlayer(state.id);
      if (!player || player.id === this.self.id) {
        return;
      }
      _results = [];
      for (k in state) {
        v = state[k];
        _results.push(player[k] = v);
      }
      return _results;
    };
    Universe.prototype.powerups = function() {
      var id, powerup, _len, _ref, _results;
      _ref = this.powerup_map;
      _results = [];
      for (powerup = 0, _len = _ref.length; powerup < _len; powerup++) {
        id = _ref[powerup];
        _results.push(powerup);
      }
      return _results;
    };
    Universe.prototype.removePowerup = function(id) {
      return delete this.powerups[id];
    };
    Universe.prototype.addPowerup = function(opts) {
      console.log("add powerup");
      return this.powerups[opts.id] = powerup.createPowerup(opts.type, opts);
    };
    Universe.prototype.addPowerups = function(new_powerups) {
      var opts, _i, _len, _results;
      _results = [];
      for (_i = 0, _len = new_powerups.length; _i < _len; _i++) {
        opts = new_powerups[_i];
        _results.push(this.addPowerup(opts));
      }
      return _results;
    };
    Universe.prototype.syncScore = function(data) {
      var player;
      player = this.getPlayer(data.id);
      return player.kills = data.score;
    };
    Universe.prototype.drawOverlay = function() {
      this.context.font = "bold 10px sans-serif";
      this.context.fillStyle = "#fff";
      this.context.fillText(this.self.name, 10, 16);
      this.drawEnergyMeter();
      this.drawHealthMeter();
      return this.drawPlayerList();
    };
    Universe.prototype.drawPowerups = function() {
      var id, powerup, _ref, _results;
      _ref = this.powerups;
      _results = [];
      for (id in _ref) {
        powerup = _ref[id];
        _results.push(powerup.draw(this.context));
      }
      return _results;
    };
    Universe.prototype.drawPlayerList = function() {
      var player, players, x, y, _i, _len, _ref, _results;
      _ref = [this.board.width - 100, 15], x = _ref[0], y = _ref[1];
      this.context.fillStyle = "#fff";
      players = this.players().sort(function(a, b) {
        return b.kills - a.kills;
      });
      this.context.font = "bold 11px sans-serif";
      this.context.fillText("Current Scores", x, y);
      this.context.font = "11px sans-serif";
      _results = [];
      for (_i = 0, _len = players.length; _i < _len; _i++) {
        player = players[_i];
        y += 12;
        _results.push(this.context.fillText("" + (parseInt(player.kills)) + " " + player.name, x, y));
      }
      return _results;
    };
    Universe.prototype.drawStats = function() {
      var toTargAngle, totarget;
      this.context.fillStyle = "#fff";
      this.context.fillText("x: " + (parseInt(this.self.x)), 10, 10);
      this.context.fillText("y: " + (parseInt(this.self.y)), 10, 20);
      this.context.fillText("angle: " + this.self.angle, 10, 30);
      this.context.fillText("speed: " + this.self.speed, 10, 40);
      this.context.fillText("thrust: " + this.self.energy, 10, 50);
      this.context.fillText("id: " + this.self.id, 10, 60);
      this.context.fillText("dead: " + this.self.dead, 10, 70);
      this.context.fillText("pressn: " + (this.self.controls.anyPressed()), 10, 80);
      if (this.self.controls.target) {
        this.context.fillText("targetx: " + this.self.controls.target.x, 10, 90);
        this.context.fillText("targetx: " + this.self.controls.target.y, 10, 100);
      } else {
        this.context.fillText("No touch target!", 10, 90);
        this.context.fillText("", 10, 100);
      }
      totarget = util.subtractVec(this.self.controls.target, this.self);
      toTargAngle = Math.PI + Math.atan2(totarget.x, totarget.y);
      this.context.fillText("Target angle: " + toTargAngle, 10, 110);
      this.context.fillText("ToTarget vectorx: " + totarget.x, 10, 120);
      this.context.fillText("ToTarget vectory: " + totarget.y, 10, 130);
      this.context.fillText("DistToTarget: " + util.distanceFrom(this.self, this.self.controls.target), 10, 140);
      return this.context.fillText("Want to turn: " + (toTargAngle - this.self.angle), 10, 150);
    };
    Universe.prototype.disableControls = function() {
      this.board.removeEventListener("mousedown");
      document.removeEventListener("keyup");
      return document.removeEventListener("keydown");
    };
    Universe.prototype.enableControls = function() {
      this.board.addEventListener("mousedown", __bind(function(e) {
        if (!(e.target === this.board && !this.self.controls.anyPressed())) {
          return;
        }
        this.self.controls.target = {
          x: e.clientX - this.board.offsetLeft,
          y: e.clientY - this.board.offsetTop
        };
        this.self.controls.mousedown = true;
        return this.is_touching = true;
      }, this), false);
      this.board.addEventListener("mousemove", __bind(function(e) {
        if (!(this.is_touching || (!this.self.controls.anyPressed() && this.self.controls.mouseDown))) {
          return;
        }
        return this.self.controls.target = {
          x: e.clientX - this.board.offsetLeft,
          y: e.clientY - this.board.offsetTop
        };
      }, this), false);
      this.board.addEventListener("mouseup", __bind(function(e) {
        this.self.controls.mouseDown = false;
        if (!this.is_touching) {
          return;
        }
        return this.is_touching = false;
      }, this), false);
      document.addEventListener("keyup", __bind(function(e) {
        switch (e.keyCode) {
          case 87:
          case 73:
            this.self.controls.wPressed = false;
            break;
          case 68:
          case 76:
            this.self.controls.dPressed = false;
            break;
          case 65:
          case 74:
            this.self.controls.aPressed = false;
            break;
          case 32:
            this.self.controls.spacePressed = false;
            break;
          case 83:
          case 75:
            this.self.controls.sPressed = false;
        }
        return this.syncSelf();
      }, this), false);
      return document.addEventListener("keydown", __bind(function(e) {
        this.self.controls.target = false;
        switch (e.keyCode) {
          case 87:
          case 73:
            this.self.controls.wPressed = true;
            break;
          case 68:
          case 76:
            this.self.controls.dPressed = true;
            break;
          case 65:
          case 74:
            this.self.controls.aPressed = true;
            break;
          case 32:
            this.self.controls.spacePressed = true;
            e.preventDefault();
            break;
          case 83:
          case 75:
            this.self.controls.sPressed = true;
        }
        return this.syncSelf();
      }, this), false);
    };
    Universe.prototype.syncSelf = function() {
      return this.sendAction("syncSelf", this.self.serialized());
    };
    Universe.prototype.connect = function() {
      this.socket = new io.Socket(window.location.hostname);
      this.socket.on('connect', __bind(function() {
        this.sendAction("initSelf", this.self.serialized(true));
        return this.startGame();
      }, this));
      this.socket.on('disconnect', __bind(function() {
        return this.stopGame();
      }, this));
      this.socket.on('message', __bind(function(msg) {
        var req;
        req = JSON.parse(msg);
        return this[req.action](req.data);
      }, this));
      return this.socket.connect();
    };
    Universe.prototype.drawEnergyMeter = function() {
      var width, x, y, _ref;
      _ref = [10, 35], x = _ref[0], y = _ref[1];
      this.context.fillStyle = "rgba(255,255,255,0.2)";
      this.context.fillRect(x, y, 110, 11);
      this.context.fillStyle = "#FF00FF";
      width = 110 * (this.self.energy / constants.maxEnergy);
      this.context.fillRect(x, y, width, 11);
      this.context.fillStyle = "rgba(0,0,0,0.5)";
      this.context.font = "9px sans-serif";
      return this.context.fillText("Energy", x + 2, y + 9);
    };
    Universe.prototype.drawHealthMeter = function() {
      var percent, x, y, _ref;
      _ref = [10, 20], x = _ref[0], y = _ref[1];
      this.context.fillStyle = "rgba(255,255,255,0.2)";
      this.context.fillRect(x, y, 110, 11);
      percent = this.self.hpPercent();
      this.context.fillStyle = percent > .2 ? "green" : "red";
      this.context.fillRect(x, y, percent * 110, 11);
      this.context.fillStyle = "rgba(0,0,0,0.5)";
      this.context.font = "9px sans-serif";
      return this.context.fillText("HP", x + 2, y + 9);
    };
    Universe.prototype.sendAction = function(action, data) {
      return this.socket.send({
        source: this.self.id,
        action: action,
        data: data
      });
    };
    Universe.prototype.checkDeath = function() {
      if (this.self.damage > constants.deadlyDamage || this.self.dead) {
        if (this.self.dead === 0) {
          console.log("" + this.self.name + " died at tick " + this.tick_count);
          this.sendAction("scorePoint", this.self.last_attacker);
          return this.self.dead = 1;
        } else if (this.self.dead >= constants.deathAnimationTime) {
          this.self.damage = 0;
          this.self.dead = 0;
          this.self.x = Math.random() * constants.universeWidth;
          this.self.y = Math.random() * constants.universeHeight;
          this.self.flash = 1;
          return this.self.energy = constants.maxEnergy;
        }
      }
    };
    return Universe;
  })();
}).call(this);
<|endoftext|>


<commit_before>(function(){

	eventUtil.EVENT_TYPE = "deviceorientation";
	var SPEC_URL_OBJECT = "http://dev.w3.org/geo/api/spec-source-orientation.html#device_orientation_event";

	var _removeEventListener = embed.hitch(eventUtil, "removeEventListener");

	dohx.add({name:eventUtil.EVENT_TYPE,
		mqcExecutionOrderBaseOffset:710000, // This number is the base offset for the execution order, the test ID gets added. Never change this number unless you know what you are doing.
		tests:[
			//
			// General tests, is it available at all, etc.
			//
			{
				id:100,
				name:"Does 'DeviceOrientationEvent' object exist?",
				definedInSpecs:["http://dev.w3.org/geo/api/spec-source-orientation.html#device_orientation_event"],
				test:function(t){
					t.assertTrue(!!window.DeviceOrientationEvent);
				}
			},
			{
				id:200,
				name:"Does addEventListener('deviceorientation') fire at all?",
				timeout: 100,
				definedInSpecs:["http://dev.w3.org/geo/api/spec-source-orientation.html"],
				test:function(t){
					eventUtil.addEventListener(function(){
						t.success(true);
					});
				},
				tearDown: _removeEventListener
			},
			{
				id:300,
				name:"Does 'window.ondeviceorientation' work?",
				timeout: 100,
				definedInSpecs:["http://dev.w3.org/geo/api/spec-source-orientation.html"],
				test:function(t){
					window.ondeviceorientation = function(e){
						t.success(true);
					};
				},
				tearDown:function(){
					window.ondeviceorientation = null;
				}
			},

			//
			// attributes
			//
			eventUtil.getPropertyExistTest({id: 1000, name: "alpha", dependsOn: [200], specs:[SPEC_URL_OBJECT]}),
			eventUtil.getPropertyTypeTest({id: 1100, name: "alpha", dependsOn: [200], expectedType: "number", specs:[SPEC_URL_OBJECT]}),
			eventUtil.getPropertyExistTest({id: 1200, name: "beta", dependsOn: [200], specs:[SPEC_URL_OBJECT]}),
			eventUtil.getPropertyTypeTest({id: 1300, name: "beta", dependsOn: [200], expectedType: "number", specs:[SPEC_URL_OBJECT]}),
			eventUtil.getPropertyExistTest({id: 1400, name: "gamma", dependsOn: [200], specs:[SPEC_URL_OBJECT]}),
			eventUtil.getPropertyTypeTest({id: 1500, name: "gamma", dependsOn: [200], expectedType: "number", specs:[SPEC_URL_OBJECT]}),
			eventUtil.getPropertyExistTest({id: 1600, name: "absolute", dependsOn: [200], specs:[SPEC_URL_OBJECT]}),
			eventUtil.getPropertyTypeTest({id: 1700, name: "absolute", dependsOn: [200], expectedType: "boolean", specs:[SPEC_URL_OBJECT]}),
			eventUtil.getPropertyExistTest({id: 1800, name: "compassCalibrated", dependsOn: [200], specs:[SPEC_URL_OBJECT]}),
			eventUtil.getPropertyTypeTest({id: 1900, name: "compassCalibrated", dependsOn: [200], expectedType: "boolean", specs:[SPEC_URL_OBJECT]}),

			//
			// real tests
			//
			{
				id:3000,
				name:"Initial position?",
				definedInSpecs:["http://dev.w3.org/geo/api/spec-source-orientation.html"],
				instructions:[
					"Click 'GO'!",
					"Place the phone 1) flat on the table 2) pointing north!"
				],
				test:function(t){
					eventUtil.addEventListener(function(e){
						dohx.showInfo("alpha: " + e.alpha + "
beta: " + e.beta + "
gamma: " + e.gamma);
					});
				},
				tearDown: eventUtil.removeEventListener
			},

//*/
		]
	});
})();
<commit_msg>Use proper tearDown<commit_after>(function(){

	eventUtil.EVENT_TYPE = "deviceorientation";
	var SPEC_URL_OBJECT = "http://dev.w3.org/geo/api/spec-source-orientation.html#device_orientation_event";

	var _removeEventListener = embed.hitch(eventUtil, "removeEventListener");

	dohx.add({name:eventUtil.EVENT_TYPE,
		mqcExecutionOrderBaseOffset:710000, // This number is the base offset for the execution order, the test ID gets added. Never change this number unless you know what you are doing.
		tests:[
			//
			// General tests, is it available at all, etc.
			//
			{
				id:100,
				name:"Does 'DeviceOrientationEvent' object exist?",
				definedInSpecs:["http://dev.w3.org/geo/api/spec-source-orientation.html#device_orientation_event"],
				test:function(t){
					t.assertTrue(!!window.DeviceOrientationEvent);
				}
			},
			{
				id:200,
				name:"Does addEventListener('deviceorientation') fire at all?",
				timeout: 100,
				definedInSpecs:["http://dev.w3.org/geo/api/spec-source-orientation.html"],
				test:function(t){
					eventUtil.addEventListener(function(){
						t.success(true);
					});
				},
				tearDown: _removeEventListener
			},
			{
				id:300,
				name:"Does 'window.ondeviceorientation' work?",
				timeout: 100,
				definedInSpecs:["http://dev.w3.org/geo/api/spec-source-orientation.html"],
				test:function(t){
					window.ondeviceorientation = function(e){
						t.success(true);
					};
				},
				tearDown:function(){
					window.ondeviceorientation = null;
				}
			},

			//
			// attributes
			//
			eventUtil.getPropertyExistTest({id: 1000, name: "alpha", dependsOn: [200], specs:[SPEC_URL_OBJECT]}),
			eventUtil.getPropertyTypeTest({id: 1100, name: "alpha", dependsOn: [200], expectedType: "number", specs:[SPEC_URL_OBJECT]}),
			eventUtil.getPropertyExistTest({id: 1200, name: "beta", dependsOn: [200], specs:[SPEC_URL_OBJECT]}),
			eventUtil.getPropertyTypeTest({id: 1300, name: "beta", dependsOn: [200], expectedType: "number", specs:[SPEC_URL_OBJECT]}),
			eventUtil.getPropertyExistTest({id: 1400, name: "gamma", dependsOn: [200], specs:[SPEC_URL_OBJECT]}),
			eventUtil.getPropertyTypeTest({id: 1500, name: "gamma", dependsOn: [200], expectedType: "number", specs:[SPEC_URL_OBJECT]}),
			eventUtil.getPropertyExistTest({id: 1600, name: "absolute", dependsOn: [200], specs:[SPEC_URL_OBJECT]}),
			eventUtil.getPropertyTypeTest({id: 1700, name: "absolute", dependsOn: [200], expectedType: "boolean", specs:[SPEC_URL_OBJECT]}),
			eventUtil.getPropertyExistTest({id: 1800, name: "compassCalibrated", dependsOn: [200], specs:[SPEC_URL_OBJECT]}),
			eventUtil.getPropertyTypeTest({id: 1900, name: "compassCalibrated", dependsOn: [200], expectedType: "boolean", specs:[SPEC_URL_OBJECT]}),

			//
			// real tests
			//
			{
				id:3000,
				name:"Initial position?",
				definedInSpecs:["http://dev.w3.org/geo/api/spec-source-orientation.html"],
				instructions:[
					"Click 'GO'!",
					"Place the phone 1) flat on the table 2) pointing north!"
				],
				test:function(t){
					eventUtil.addEventListener(function(e){
						dohx.showInfo("alpha: " + e.alpha + "
beta: " + e.beta + "
gamma: " + e.gamma);
					});
				},
				tearDown: _removeEventListener
			},

//*/
		]
	});
})();
<|endoftext|>


<commit_before>/*
 * html-angular-validate
 * https://github.com/nikestep/html-angular-validate
 *
 * Copyright (c) 2015 Nik Estep
 * Licensed under the MIT license.
 */
'use strict';

// Load our dependencies
var async = require('async');
var extend = require('node.extend');
var filendir = require('filendir');
var fs = require('fs');
var globule = require('globule');
var Promise = require('promise');
var tmp = require('temporary');
var w3cjs = require('w3cjs');

require('string.prototype.endswith');

// Set the default options
var default_opts = {
  angular: true,
  customtags: [],
  customattrs: [],
  wrapping: {},
  relaxerror: [],
  tmplext: 'tmpl.html',
  doctype: 'HTML5',
  charset: 'utf-8',
  reportpath: 'html-angular-validate-report.json',
  w3clocal: null,
  w3cproxy: null,
  concurrentjobs: 1,
  maxvalidateattempts: 3
};

var checkRelaxed = function(errmsg, options) {
  for (var i = 0; i < options.relaxerror.length; i += 1) {
    if (errmsg.indexOf(options.relaxerror[i]) !== -1) {
      return true;
    }
  }
  return false;
};

var checkCustomTags = function(errmsg, options) {
  for (var i = 0; i < options.customtags.length; i += 1) {
    var re = new RegExp('^Element (.?)' +
      options.customtags[i] +
      '(.?) not allowed as child (.*)');
    if (re.test(errmsg)) {
      return true;
    }
  }
  return false;
};

var checkCustomAttrs = function(errmsg, options) {
  for (var i = 0; i < options.customattrs.length; i += 1) {
    var re = new RegExp('Attribute (.?)' +
      options.customattrs[i] +
      '(.?) not allowed on element (.*) at this point.');
    if (re.test(errmsg)) {
      return true;
    }
  }
  return false;
};

var validate = function(file, callback) {
  var options = this;
  var temppath = file.path;

  // If this is a templated file, we need to wrap it as a full
  // document in a temporary file
  var tfile = null;
  if (file.istmpl) {
    // Create a temporary file
    tfile = new tmp.File();

    // Store temp path as one to pass to validator
    temppath = tfile.path;

    // Create a wrapped file to pass to the validator
    var content = fs.readFileSync(file.path, {
      encoding: 'utf8'
    }).trim();
    for (var key in options.wrapping) {
      if (options.wrapping.hasOwnProperty(key)) {
        var tag = '^<' + key + '[^>]*>';
        if (content.match(tag)) {
          content = options.wrapping[key].replace('{0}', content);
          break;
        }
      }
    }

    // Build temporary file
    fs.writeFileSync(temppath,
      '<!DOCTYPE html>\n\n<title>Dummy</title>\n\n' +
      content +
      '\n\n');
  }

  // Do validation
  var results = w3cjs.validate({
    file: temppath,
    output: 'json',
    doctype: this.doctype,
    charset: this.charset,
    proxy: this.w3cproxy,
    callback: function(res) {
      // Validate result
      if (res === undefined || res.messages === undefined) {
        // Something went wrong
        //   See if we should try again or fail this file and
        //   move on
        if (file.attempts < options.maxvalidateattempts) {
          // Increment the attempt count and try again
          file.attempts += 1;
          validate(file, callback);
        } else {
          // Fail the file and stop remaining validations
          // Clean up if it is a template file
          file.seenerrs = true;
          file.errs = [{
            line: 0,
            col: 0,
            msg: 'Unable to validate file'
          }];
          if (tfile !== null) {
            tfile.unlink();
          }
          callback('Unable to check file', file);
        }
      } else {
        // Handle results
        var errFound = false;
        for (var i = 0; i < res.messages.length; i += 1) {
          // See if this error message is valid
          if (!checkRelaxed(res.messages[i].message, options) &&
            !checkCustomTags(res.messages[i].message, options) &&
            !checkCustomAttrs(res.messages[i].message, options)) {
            // Store the error message
            errFound = true;
            file.seenerrs = true;
            file.errs.push({
              line: (file.istmpl) ? res.messages[i].lastLine - 4 : res.messages[i].lastLine,
              col: res.messages[i].lastColumn,
              msg: res.messages[i].message
            });
          }
        }

        // Clean up temporary file if needed
        if (tfile !== null) {
          tfile.unlink();
        }

        // Callback: no halting error, success indicator
        callback(null, file);
      }
    }
  });
};

var finished = function(files, options, fullfill, reject) {
  // Get the failed files
  var failedFiles = files.filter(function(file) {
    return file.seenerrs;
  });

  // Build the result object
  var result = {
    datetime: new Date(),
    allpassed: failedFiles.length == 0,
    fileschecked: files.length,
    filessucceeded: files.length - failedFiles.length,
    filesfailed: failedFiles.length,
    failed: failedFiles.map(function(file) {
      return {
        filepath: file.path,
        numerrs: file.errs.length,
        errors: file.errs.map(function(err) {
          var out = {
            msg: err.msg
          };
          if (err.line !== undefined) {
            out.line = err.line;
            out.col = err.col;
          }
          return out;
        })
      };
    })
  };

  // Output report if necessary
  if (options.reportpath !== null) {
    // Write the report out
    filendir.writeFileSync(options.reportpath, JSON.stringify(result));
  }

  // Send result to promise
  fullfill(result);
};

module.exports = {
  validate: function(fileSrcs, opts) {
    // Wrap inside a promise object
    return new Promise(function(fullfill, reject) {
      // Merge options
      var options = extend(JSON.parse(JSON.stringify(default_opts)), opts);

      // Parse wildcard '*' to RegExp '(.*)'
      ['customtags', 'customattrs'].forEach(function(prop) {
        for (var i = 0; i < options[prop].length; i += 1) {
          options[prop][i] = options[prop][i].replace(/\*/g, '(.*)');
        }
      });

      // Add attributes to ignore if this is for AngularJS
      if (options.angular) {
        options.customtags.push('ng-(.*)');
        options.customtags.push('ui-(.*)');
        options.customattrs.push('ng-(.*)');
        options.customattrs.push('ui-(.*)');
        options.customattrs.push('on');
      }

      // Ignore certain default warnings
      options.relaxerror.push('The Content-Type was');
      options.relaxerror.push('The character encoding was not declared');
      options.relaxerror.push('Using the schema for HTML with');
      options.relaxerror.push('Using the schema for HTML5 +');

      // Delete an exist report if present
      if (options.reportpath !== null && fs.existsSync(options.reportpath)) {
        fs.unlinkSync(options.reportpath);
      }

      // Pass along local w3c server if set
      if (options.w3clocal !== null) {
        w3cjs.setW3cCheckUrl(options.w3clocal);
      }

      // Get a list of files to validate
      var files = globule.find({
        src: fileSrcs,
        filter: 'isFile'
      }).map(function(file) {
        return {
          path: file,
          istmpl: file.endsWith(options.tmplext),
          attempts: 0,
          seenerrs: false,
          errs: []
        }
      });

      // Check that we got files
      if (files.length === 0) {
        reject('No files found to match');
      }

      // Start the validation
      async.mapLimit(
        files,
        options.concurrentjobs,
        validate.bind(options),
        function(err, results) {
          finished(results, options, fullfill, reject);
        });
    });
  }
};
<commit_msg>add a deep copy of the validation options<commit_after>/*
 * html-angular-validate
 * https://github.com/nikestep/html-angular-validate
 *
 * Copyright (c) 2015 Nik Estep
 * Licensed under the MIT license.
 */
'use strict';

// Load our dependencies
var async = require('async');
var extend = require('node.extend');
var filendir = require('filendir');
var fs = require('fs');
var globule = require('globule');
var Promise = require('promise');
var tmp = require('temporary');
var w3cjs = require('w3cjs');

require('string.prototype.endswith');

// Set the default options
var default_opts = {
  angular: true,
  customtags: [],
  customattrs: [],
  wrapping: {},
  relaxerror: [],
  tmplext: 'tmpl.html',
  doctype: 'HTML5',
  charset: 'utf-8',
  reportpath: 'html-angular-validate-report.json',
  w3clocal: null,
  w3cproxy: null,
  concurrentjobs: 1,
  maxvalidateattempts: 3
};

var checkRelaxed = function(errmsg, options) {
  for (var i = 0; i < options.relaxerror.length; i += 1) {
    if (errmsg.indexOf(options.relaxerror[i]) !== -1) {
      return true;
    }
  }
  return false;
};

var checkCustomTags = function(errmsg, options) {
  for (var i = 0; i < options.customtags.length; i += 1) {
    var re = new RegExp('^Element (.?)' +
      options.customtags[i] +
      '(.?) not allowed as child (.*)');
    if (re.test(errmsg)) {
      return true;
    }
  }
  return false;
};

var checkCustomAttrs = function(errmsg, options) {
  for (var i = 0; i < options.customattrs.length; i += 1) {
    var re = new RegExp('Attribute (.?)' +
      options.customattrs[i] +
      '(.?) not allowed on element (.*) at this point.');
    if (re.test(errmsg)) {
      return true;
    }
  }
  return false;
};

var validate = function(file, callback) {
  var options = this;
  var temppath = file.path;

  // If this is a templated file, we need to wrap it as a full
  // document in a temporary file
  var tfile = null;
  if (file.istmpl) {
    // Create a temporary file
    tfile = new tmp.File();

    // Store temp path as one to pass to validator
    temppath = tfile.path;

    // Create a wrapped file to pass to the validator
    var content = fs.readFileSync(file.path, {
      encoding: 'utf8'
    }).trim();
    for (var key in options.wrapping) {
      if (options.wrapping.hasOwnProperty(key)) {
        var tag = '^<' + key + '[^>]*>';
        if (content.match(tag)) {
          content = options.wrapping[key].replace('{0}', content);
          break;
        }
      }
    }

    // Build temporary file
    fs.writeFileSync(temppath,
      '<!DOCTYPE html>\n\n<title>Dummy</title>\n\n' +
      content +
      '\n\n');
  }

  // Do validation
  var results = w3cjs.validate({
    file: temppath,
    output: 'json',
    doctype: this.doctype,
    charset: this.charset,
    proxy: this.w3cproxy,
    callback: function(res) {
      // Validate result
      if (res === undefined || res.messages === undefined) {
        // Something went wrong
        //   See if we should try again or fail this file and
        //   move on
        if (file.attempts < options.maxvalidateattempts) {
          // Increment the attempt count and try again
          file.attempts += 1;
          validate(file, callback);
        } else {
          // Fail the file and stop remaining validations
          // Clean up if it is a template file
          file.seenerrs = true;
          file.errs = [{
            line: 0,
            col: 0,
            msg: 'Unable to validate file'
          }];
          if (tfile !== null) {
            tfile.unlink();
          }
          callback('Unable to check file', file);
        }
      } else {
        // Handle results
        var errFound = false;
        for (var i = 0; i < res.messages.length; i += 1) {
          // See if this error message is valid
          if (!checkRelaxed(res.messages[i].message, options) &&
            !checkCustomTags(res.messages[i].message, options) &&
            !checkCustomAttrs(res.messages[i].message, options)) {
            // Store the error message
            errFound = true;
            file.seenerrs = true;
            file.errs.push({
              line: (file.istmpl) ? res.messages[i].lastLine - 4 : res.messages[i].lastLine,
              col: res.messages[i].lastColumn,
              msg: res.messages[i].message
            });
          }
        }

        // Clean up temporary file if needed
        if (tfile !== null) {
          tfile.unlink();
        }

        // Callback: no halting error, success indicator
        callback(null, file);
      }
    }
  });
};

var finished = function(files, options, fullfill, reject) {
  // Get the failed files
  var failedFiles = files.filter(function(file) {
    return file.seenerrs;
  });

  // Build the result object
  var result = {
    datetime: new Date(),
    allpassed: failedFiles.length == 0,
    fileschecked: files.length,
    filessucceeded: files.length - failedFiles.length,
    filesfailed: failedFiles.length,
    failed: failedFiles.map(function(file) {
      return {
        filepath: file.path,
        numerrs: file.errs.length,
        errors: file.errs.map(function(err) {
          var out = {
            msg: err.msg
          };
          if (err.line !== undefined) {
            out.line = err.line;
            out.col = err.col;
          }
          return out;
        })
      };
    })
  };

  // Output report if necessary
  if (options.reportpath !== null) {
    // Write the report out
    filendir.writeFileSync(options.reportpath, JSON.stringify(result));
  }

  // Send result to promise
  fullfill(result);
};

module.exports = {
  validate: function(fileSrcs, opts) {
    opts = JSON.parse(JSON.stringify(opts));

    // Wrap inside a promise object
    return new Promise(function(fullfill, reject) {
      // Merge options
      var options = extend(JSON.parse(JSON.stringify(default_opts)), opts);

      // Parse wildcard '*' to RegExp '(.*)'
      ['customtags', 'customattrs'].forEach(function(prop) {
        for (var i = 0; i < options[prop].length; i += 1) {
          options[prop][i] = options[prop][i].replace(/\*/g, '(.*)');
        }
      });

      // Add attributes to ignore if this is for AngularJS
      if (options.angular) {
        options.customtags.push('ng-(.*)');
        options.customtags.push('ui-(.*)');
        options.customattrs.push('ng-(.*)');
        options.customattrs.push('ui-(.*)');
        options.customattrs.push('on');
      }

      // Ignore certain default warnings
      options.relaxerror.push('The Content-Type was');
      options.relaxerror.push('The character encoding was not declared');
      options.relaxerror.push('Using the schema for HTML with');
      options.relaxerror.push('Using the schema for HTML5 +');

      // Delete an exist report if present
      if (options.reportpath !== null && fs.existsSync(options.reportpath)) {
        fs.unlinkSync(options.reportpath);
      }

      // Pass along local w3c server if set
      if (options.w3clocal !== null) {
        w3cjs.setW3cCheckUrl(options.w3clocal);
      }

      // Get a list of files to validate
      var files = globule.find({
        src: fileSrcs,
        filter: 'isFile'
      }).map(function(file) {
        return {
          path: file,
          istmpl: file.endsWith(options.tmplext),
          attempts: 0,
          seenerrs: false,
          errs: []
        }
      });

      // Check that we got files
      if (files.length === 0) {
        reject('No files found to match');
      }

      // Start the validation
      async.mapLimit(
        files,
        options.concurrentjobs,
        validate.bind(options),
        function(err, results) {
          finished(results, options, fullfill, reject);
        });
    });
  }
};
<|endoftext|>


<commit_before>'use strict';
var jsonlint = require('jsonlint-lines-primitives');
var reference = require('./reference');
var parseCSSColor = require('csscolorparser').parseCSSColor;

module.exports = {};
module.exports.value = value;

['v2','v3','v4'].forEach(function(version) {
    var ref = reference(version);
    // Create validator for version
    module.exports[version] = validator(ref);
    // Create validators for each container ('style', 'bucket', etc.)
    for (var container in ref) {
        if (typeof ref[container] !== 'object') continue;
        if (ref[container].type && typeof ref[container].type !== 'object') continue;
        module.exports[version][container] = validateContainer(ref, container);
    }
});

// Generates a validation function for a container object.
function validateContainer(ref, container) {
    return function (property, val, line) {
        var errors = [];
        var spec = ref[container][property];
        if (!spec) {
            errors.push({
                message: container + ' property unrecognized: ' + property,
                line: line
            });
        } else {
            value(property, val, {}, ref, spec, errors);
        }
        return errors;
    };
}

function validator(ref) {
    var validate = function(str) {
        var style, errors = [];
        try {
            style = jsonlint.parse(str.toString());
        } catch(e) {
            var match = e.message.match(/line (\d+)/),
                lineNumber = 0;
            if (match) lineNumber = parseInt(match[1], 10);
            return [{
                line: lineNumber - 1,
                message: e.message,
                error: e
            }];
        }

        style = jsonlint.parse(str.toString());

        value('', style, style.constants||{}, ref, ref.$root, errors);

        return errors;
    };
    return validate;
}

// Main recursive validation function. Tracks:
//
// - key: string representing location of validation in style tree. Used only
//   for more informative error reporting. Example: `styles.default.road`
// - val: current value from style being evaluated. May be anything from a
//   high level object that needs to be descended into deeper or a simple
//   scalar value.
// - constants: object of constants for the style to resolve constant values.
// - ref: full reference object. Used if any point in validation refers to
//   a type defined at the root-level of the reference object.
// - spec: current spec being evaluated. Tracks val.
// - errors: array of errors passed by reference.
//
// Returns true if the `val` passed (and any children recursed into) pass
// the validation defined by `spec`. Returns false if validation fails.
// Validation errors will be pushed onto the errors array.
function value(key, val, constants, ref, spec, errors) {
    var pass = true;

    var line = val.__line__;

    val = unbundle(val);

    // Resolve constants.
    if (typeof val === 'string' && constants[val] !== undefined) val = constants[val];

    val = unbundle(val);

    // Spec specifies a non-native type (bucket, style, etc.)
    if (spec.type && ref[spec.type]) {
        return value(key, val, constants, ref, ref[spec.type], errors);
    // Spec specifies a type, but val must be an array of those (layers only atm).
    } else if (spec.type === 'array' && spec.value) {
        if (Array.isArray(val)) {
            if (spec.length && val.length !== spec.length) {
                errors.push({
                    message: key + ': array length ' + spec.length + ' expected, length ' + val.length + ' found',
                    line: line
                });
                return false;
            }
            for (var i = 0; i < val.length; i++) {
                var valspec = ref[spec.value]||spec.value;
                if (typeof valspec === ('string' | 'number')) {
                    if (spec.function && typeof val[i] === 'object') {
                        pass = value(key, val[i], constants, ref, ref.function, errors);
                    } else {
                        pass = validateNative(key + '[' + i + ']', val[i], valspec, errors) && pass;
                    }
                } else {
                    pass = value(key + '[' + i + ']', val[i], constants, ref, valspec, errors) && pass;
                }
            }
            return pass;
        } else {
            errors.push({
                message: key + ': array expected, ' + typeof val + ' found',
                line: line
            });
            return false;
        }
    // Spec specifies an array of specs val may match.
    } else if (Array.isArray(spec)) {
        var sub = [];
        var valid = spec.some(function(s) {
            var spec = typeof s === 'string' ? (ref[s] || s) : s;
            if (typeof spec === 'string') {
                return validateNative(key, val, spec, sub);
            } else {
                return value(key, val, constants, ref, spec, sub);
            }
        });
        if (!valid) sub.forEach(function(err) { errors.push(err); });
        return valid;
    // Val is a function.
    } else if (spec.function && typeof val === 'object' && !Array.isArray(val)) {
        return value(key, val, constants, ref, ref.function, errors);
    // Val must be one of enumerated values.
    } else if (spec.type === 'enum') {
        return validateEnum(key, val, spec.values, errors);
    // Val must match a type.
    } else if (spec.type && typeof spec.type === 'string') {
        return validateNative(key, val, spec.type, errors);
    // No type defined: spec is a container. Val must be an object
    // and must have keys matching the container object definition.
    } else {
        for (var k in val) {
            var childkey = (key ? key + '.' : key) + k;
            var speckey = k.split('.')[0]; // treat 'style.*' as 'style'
            var def = spec[speckey] || spec['*'] || undefined;
            if (!def) {
                errors.push({
                    message: spec.__name__ + ' property unrecognized: ' + k,
                    line: line
                });
                pass = false;
                continue;
            }
            pass = value(childkey, val[k], constants, ref, def, errors) && pass;
        }
        for (var l in spec) {
            if (spec[l].required && spec[l]['default'] === undefined && val[l] === undefined) {
                errors.push({
                    message: spec.__name__ + ' property ' + l + ' required',
                    line: line
                });
                pass = false;
            }
        }
        return pass;
    }
}

function unbundle(_) {
    if (_ instanceof Number ||
        _ instanceof String ||
        _ instanceof Boolean) {
        return _.valueOf();
    } else {
        return _;
    }
}

function validateNative(key, val, spec, errors) {
    if (spec === '*') return true;

    var line = val.__line__;

    val = unbundle(val);

    var type = Array.isArray(val) ? 'array' : typeof val;

    if (spec === 'color') {
        if (type !== 'string') {
            errors.push({
                message: key + ': ' + spec + ' expected, ' + type + ' found',
                line: line
            });
            return false;
        } else if (parseCSSColor(val) === null) {
            errors.push({
                message: key + ': ' + spec + ' expected, ' + val + ' found',
                line: line
            });
            return false;
        } else {
            return true;
        }
    }

    if (type !== spec) {
        errors.push({
            message: key + ': ' + spec + ' expected, ' + (typeof val) + ' found',
            line: val ? line : null
        });
        return false;
    } else {
        return true;
    }
}

function validateEnum(key, val, spec, errors) {
    var line = val.__line__;
    val = unbundle(val);
    if (spec.indexOf(val) === -1) {
        errors.push({
            message: key + ': expected one of [' + spec.join(', ') + '], ' + val + ' found',
            line: line
        });
        return false;
    } else {
        return true;
    }
}
<commit_msg>actual fix for number arrays<commit_after>'use strict';
var jsonlint = require('jsonlint-lines-primitives');
var reference = require('./reference');
var parseCSSColor = require('csscolorparser').parseCSSColor;

module.exports = {};
module.exports.value = value;

['v2','v3','v4'].forEach(function(version) {
    var ref = reference(version);
    // Create validator for version
    module.exports[version] = validator(ref);
    // Create validators for each container ('style', 'bucket', etc.)
    for (var container in ref) {
        if (typeof ref[container] !== 'object') continue;
        if (ref[container].type && typeof ref[container].type !== 'object') continue;
        module.exports[version][container] = validateContainer(ref, container);
    }
});

// Generates a validation function for a container object.
function validateContainer(ref, container) {
    return function (property, val, line) {
        var errors = [];
        var spec = ref[container][property];
        if (!spec) {
            errors.push({
                message: container + ' property unrecognized: ' + property,
                line: line
            });
        } else {
            value(property, val, {}, ref, spec, errors);
        }
        return errors;
    };
}

function validator(ref) {
    var validate = function(str) {
        var style, errors = [];
        try {
            style = jsonlint.parse(str.toString());
        } catch(e) {
            var match = e.message.match(/line (\d+)/),
                lineNumber = 0;
            if (match) lineNumber = parseInt(match[1], 10);
            return [{
                line: lineNumber - 1,
                message: e.message,
                error: e
            }];
        }

        style = jsonlint.parse(str.toString());

        value('', style, style.constants||{}, ref, ref.$root, errors);

        return errors;
    };
    return validate;
}

// Main recursive validation function. Tracks:
//
// - key: string representing location of validation in style tree. Used only
//   for more informative error reporting. Example: `styles.default.road`
// - val: current value from style being evaluated. May be anything from a
//   high level object that needs to be descended into deeper or a simple
//   scalar value.
// - constants: object of constants for the style to resolve constant values.
// - ref: full reference object. Used if any point in validation refers to
//   a type defined at the root-level of the reference object.
// - spec: current spec being evaluated. Tracks val.
// - errors: array of errors passed by reference.
//
// Returns true if the `val` passed (and any children recursed into) pass
// the validation defined by `spec`. Returns false if validation fails.
// Validation errors will be pushed onto the errors array.
function value(key, val, constants, ref, spec, errors) {
    var pass = true;

    var line = val.__line__;

    val = unbundle(val);

    // Resolve constants.
    if (typeof val === 'string' && constants[val] !== undefined) val = constants[val];

    val = unbundle(val);

    // Spec specifies a non-native type (bucket, style, etc.)
    if (spec.type && ref[spec.type]) {
        return value(key, val, constants, ref, ref[spec.type], errors);
    // Spec specifies a type, but val must be an array of those (layers only atm).
    } else if (spec.type === 'array' && spec.value) {
        if (Array.isArray(val)) {
            if (spec.length && val.length !== spec.length) {
                errors.push({
                    message: key + ': array length ' + spec.length + ' expected, length ' + val.length + ' found',
                    line: line
                });
                return false;
            }
            for (var i = 0; i < val.length; i++) {
                var valspec = ref[spec.value]||spec.value;
                if (typeof valspec === 'string' || typeof valspec === 'number') {
                    if (spec.function && Array.isArray(val[i])) {
                        pass = value(key, val[i], constants, ref, ref.function, errors);
                    } else {
                        pass = validateNative(key + '[' + i + ']', val[i], valspec, errors) && pass;
                    }
                } else {
                    pass = value(key + '[' + i + ']', val[i], constants, ref, valspec, errors) && pass;
                }
            }
            return pass;
        } else {
            errors.push({
                message: key + ': array expected, ' + typeof val + ' found',
                line: line
            });
            return false;
        }
    // Spec specifies an array of specs val may match.
    } else if (Array.isArray(spec)) {
        var sub = [];
        var valid = spec.some(function(s) {
            var spec = typeof s === 'string' ? (ref[s] || s) : s;
            if (typeof spec === 'string') {
                return validateNative(key, val, spec, sub);
            } else {
                return value(key, val, constants, ref, spec, sub);
            }
        });
        if (!valid) sub.forEach(function(err) { errors.push(err); });
        return valid;
    // Val is a function.
    } else if (spec.function && typeof val === 'object' && !Array.isArray(val)) {
        return value(key, val, constants, ref, ref.function, errors);
    // Val must be one of enumerated values.
    } else if (spec.type === 'enum') {
        return validateEnum(key, val, spec.values, errors);
    // Val must match a type.
    } else if (spec.type && typeof spec.type === 'string') {
        return validateNative(key, val, spec.type, errors);
    // No type defined: spec is a container. Val must be an object
    // and must have keys matching the container object definition.
    } else {
        for (var k in val) {
            var childkey = (key ? key + '.' : key) + k;
            var speckey = k.split('.')[0]; // treat 'style.*' as 'style'
            var def = spec[speckey] || spec['*'] || undefined;
            if (!def) {
                errors.push({
                    message: spec.__name__ + ' property unrecognized: ' + k,
                    line: line
                });
                pass = false;
                continue;
            }
            pass = value(childkey, val[k], constants, ref, def, errors) && pass;
        }
        for (var l in spec) {
            if (spec[l].required && spec[l]['default'] === undefined && val[l] === undefined) {
                errors.push({
                    message: spec.__name__ + ' property ' + l + ' required',
                    line: line
                });
                pass = false;
            }
        }
        return pass;
    }
}

function unbundle(_) {
    if (_ instanceof Number ||
        _ instanceof String ||
        _ instanceof Boolean) {
        return _.valueOf();
    } else {
        return _;
    }
}

function validateNative(key, val, spec, errors) {
    if (spec === '*') return true;

    var line = val.__line__;

    val = unbundle(val);

    var type = Array.isArray(val) ? 'array' : typeof val;

    if (spec === 'color') {
        if (type !== 'string') {
            errors.push({
                message: key + ': ' + spec + ' expected, ' + type + ' found',
                line: line
            });
            return false;
        } else if (parseCSSColor(val) === null) {
            errors.push({
                message: key + ': ' + spec + ' expected, ' + val + ' found',
                line: line
            });
            return false;
        } else {
            return true;
        }
    }

    if (type !== spec) {
        errors.push({
            message: key + ': ' + spec + ' expected, ' + (typeof val) + ' found',
            line: val ? line : null
        });
        return false;
    } else {
        return true;
    }
}

function validateEnum(key, val, spec, errors) {
    var line = val.__line__;
    val = unbundle(val);
    if (spec.indexOf(val) === -1) {
        errors.push({
            message: key + ': expected one of [' + spec.join(', ') + '], ' + val + ' found',
            line: line
        });
        return false;
    } else {
        return true;
    }
}
<|endoftext|>


<commit_before>/**
 * @fileoverview Stylish reporter
 * @author Sindre Sorhus
 */
"use strict";

var chalk = require("chalk"),
    table = require("text-table");

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------

/**
 * Given a word and a count, append an s if count is not one.
 * @param {string} word A word in its singular form.
 * @param {int} count A number controlling whether word should be pluralized.
 * @returns {string} The original word with an s on the end if count is not one.
 */
function pluralize(word, count) {
    return (count === 1 ? word : word + "s");
}

//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------

module.exports = function(results) {

    var output = "\n",
        total = 0,
        errors = 0,
        warnings = 0,
        summaryColor = "yellow";

    results.forEach(function(result) {
        var messages = result.messages;

        if (messages.length === 0) {
            return;
        }

        total += messages.length;
        output += chalk.underline(result.filePath) + "\n";

        output += table(
            messages.map(function(message) {
                var messageType;

                if (message.fatal || message.severity === 2) {
                    messageType = chalk.red("error");
                    summaryColor = "red";
                    errors++;
                } else {
                    messageType = chalk.yellow("warning");
                    warnings++;
                }

                return [
                    "",
                    message.line || 0,
                    message.column || 0,
                    messageType,
                    message.message.replace(/\.$/, ""),
                    chalk.gray(message.ruleId || "")
                ];
            }),
            {
                align: ["", "r", "l"],
                stringLength: function(str) {
                    return chalk.stripColor(str).length;
                }
            }
        ).split("\n").map(function(el) {
            return el.replace(/(\d+)\s+(\d+)/, function(m, p1, p2) {
                return chalk.gray(p1 + ":" + p2);
            });
        }).join("\n") + "\n\n";
    });

    if (total > 0) {
        output += chalk[summaryColor].bold([
            "\u2716 ", total, pluralize(" problem", total),
            " (", errors, pluralize(" error", errors), ", ",
            warnings, pluralize(" warning", warnings), ")\n"
        ].join(""));
    }

    return total > 0 ? output : "";
};
<commit_msg>Fix: gray text was invisible on Solarized Dark theme (fixes #4886)<commit_after>/**
 * @fileoverview Stylish reporter
 * @author Sindre Sorhus
 */
"use strict";

var chalk = require("chalk"),
    table = require("text-table");

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------

/**
 * Given a word and a count, append an s if count is not one.
 * @param {string} word A word in its singular form.
 * @param {int} count A number controlling whether word should be pluralized.
 * @returns {string} The original word with an s on the end if count is not one.
 */
function pluralize(word, count) {
    return (count === 1 ? word : word + "s");
}

//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------

module.exports = function(results) {

    var output = "\n",
        total = 0,
        errors = 0,
        warnings = 0,
        summaryColor = "yellow";

    results.forEach(function(result) {
        var messages = result.messages;

        if (messages.length === 0) {
            return;
        }

        total += messages.length;
        output += chalk.underline(result.filePath) + "\n";

        output += table(
            messages.map(function(message) {
                var messageType;

                if (message.fatal || message.severity === 2) {
                    messageType = chalk.red("error");
                    summaryColor = "red";
                    errors++;
                } else {
                    messageType = chalk.yellow("warning");
                    warnings++;
                }

                return [
                    "",
                    message.line || 0,
                    message.column || 0,
                    messageType,
                    message.message.replace(/\.$/, ""),
                    chalk.dim(message.ruleId || "")
                ];
            }),
            {
                align: ["", "r", "l"],
                stringLength: function(str) {
                    return chalk.stripColor(str).length;
                }
            }
        ).split("\n").map(function(el) {
            return el.replace(/(\d+)\s+(\d+)/, function(m, p1, p2) {
                return chalk.dim(p1 + ":" + p2);
            });
        }).join("\n") + "\n\n";
    });

    if (total > 0) {
        output += chalk[summaryColor].bold([
            "\u2716 ", total, pluralize(" problem", total),
            " (", errors, pluralize(" error", errors), ", ",
            warnings, pluralize(" warning", warnings), ")\n"
        ].join(""));
    }

    return total > 0 ? output : "";
};
<|endoftext|>


<commit_before>// whiskers.js templating library

// the namespace
var whiskers = {};

// a cache for templates
whiskers.cache = {};

// expand all partials
whiskers.expand = function(template, partials, indent) {
  // convert to string, empty if false
  template = (template || '')+'';
  // drop trailing newlines and prepend indent to each line
  indent = indent || '';
  template = indent + template.replace(/\n+$/, '').replace(/\n/g, indent || '\n');
  return template.replace(/(\n[ \t]+|)(\\*){>([\w.]+)}/g, function(str, indent, escapeChar, key) {
    // if tag is escaped return it untouched with first backslash removed
    if (escapeChar) return str.replace('\\', '');
    // get partial, empty if not found
    try {
      template = eval('partials.'+key);
    } catch (e) {
      template = '';
    }
    // recurse to expand any partials in this partial
    return whiskers.expand(template, partials, indent);
  });
};

// compile template to js string for eval
whiskers.compile = function(template) {
  // convert to string, empty if false
  template = (template || '')+'';

  // escape backslashes and single quotes
  template = template.replace(/\\/g, '\\\\').replace(/\'/g, '\\\'');

  // replace simple key tags (like {foo})
  template = template.replace(/(\\*){([\w.]+)}/g, function(str, escapeChar, key) {
    if (escapeChar) return str.replace('\\\\', '');
    return '\'+v(c,\''+key+'\')+\'';
  });

  // to check for correcting logic mistakes
  var levels = {'for':0, 'if': 0};

  // replace logic tags (like {for foo in bar} and {if foo})
  template = template.replace(/(\n[ \t]*|)(\\*){(\/?)(for|if|)( +|)(not +|)((\w+) +in +|)([\w.]+|)}(?:([ \t]*(?=\n))|)/g, function(str, newlineBefore, escapeChar, close, statement, statementSpace, ifNot, forIn, iterVar, key, newlineAfter, offset, s) {
    if (escapeChar) return str.replace('\\\\', '');
    // if a logic tag is on a line by itself remove preceding newline and
    // whitespace
    if (newlineBefore && newlineAfter !== undefined) {
      newlineBefore = '';
    }
    // opening tags
    if (statement && statementSpace && key) {
      levels[statement]++;
      // {for foo in bar}
      if (statement === 'for' && iterVar) {
        return newlineBefore+'\';var '+iterVar+'A=v(c,\''+key+'\');for(var '+iterVar+'I=0;'+iterVar+'I<'+iterVar+'A.length;'+iterVar+'I++){c[\''+iterVar+'\']='+iterVar+'A['+iterVar+'I];b+=\'';
      }
      // {if foo} or {if not foo}
      if (statement === 'if') {
        return newlineBefore+'\';if('+(ifNot?'!':'')+'v(c,\''+key+'\')){b+=\'';
      }
    }
    // closing tags ({/for} or {/if})
    if (close && statement) {
      if (levels[statement] === 0) {
        console.warn('extra {/'+statement+'} ignored');
        return '';
      } else {
        levels[statement]--;
        return newlineBefore+'\';}b+=\'';
      }
    }
    // not a tag, don't replace
    return str;
  });

  // close extra fors and ifs
  for (statement in levels) {
    for (var i=0; i<levels[statement]; i++) {
      console.warn('extra "'+statement+'" closed at end of template');
      template = template+'\';}b+=\'';
    }
  }

  // escape newlines for eval
  template = template.replace(/\n/g, '\\n');

  // wrap in function and return
  // c is context, b is buffer, v is getValue, r is recurse, o is object,
  // k is key, s is splitKey, f is first
  return '(function(){return function(c){var v=function(o,k){var r=function(o,s){if(s.length===0){if(typeof o===\'function\')return o(c);return o}var f=s.shift();if(!o.hasOwnProperty(f))return \'\';return r(o[f],s)};var s=k.split(\'.\');return r(o,s)};var b=\''+template+'\';return b}})()';
};

// main function for rendering templates
whiskers.render = function(template, context, partials) {
  template = whiskers.expand(template, partials);
  // use cached if it exists
  if (whiskers.cache[template]) return whiskers.cache[template](context);
  // compile and cache
  whiskers.cache[template] = eval(whiskers.compile(template));
  return whiskers.cache[template](context);
};

// commonjs
if (typeof module === 'object') {
  module.exports = whiskers;
}
<commit_msg>Eval for value in eval string<commit_after>// whiskers.js templating library

// the namespace
var whiskers = {};

// a cache for templates
whiskers.cache = {};

// expand all partials
whiskers.expand = function(template, partials, indent) {
  // convert to string, empty if false
  template = (template || '')+'';
  // drop trailing newlines and prepend indent to each line
  indent = indent || '';
  template = indent + template.replace(/\n+$/, '').replace(/\n/g, indent || '\n');
  return template.replace(/(\n[ \t]+|)(\\*){>([\w.]+)}/g, function(str, indent, escapeChar, key) {
    // if tag is escaped return it untouched with first backslash removed
    if (escapeChar) return str.replace('\\', '');
    // get partial, empty if not found
    try {
      template = eval('partials.'+key);
    } catch (e) {
      template = '';
    }
    // recurse to expand any partials in this partial
    return whiskers.expand(template, partials, indent);
  });
};

// compile template to js string for eval
whiskers.compile = function(template) {
  // convert to string, empty if false
  template = (template || '')+'';

  // escape backslashes and single quotes
  template = template.replace(/\\/g, '\\\\').replace(/\'/g, '\\\'');

  // replace simple key tags (like {foo})
  template = template.replace(/(\\*){([\w.]+)}/g, function(str, escapeChar, key) {
    if (escapeChar) return str.replace('\\\\', '');
    return '\'+g(\''+key+'\')+\'';
  });

  // to check for correcting logic mistakes
  var levels = {'for':0, 'if': 0};

  // replace logic tags (like {for foo in bar} and {if foo})
  template = template.replace(/(\n[ \t]*|)(\\*){(\/?)(for|if|)( +|)(not +|)((\w+) +in +|)([\w.]+|)}(?:([ \t]*(?=\n))|)/g, function(str, newlineBefore, escapeChar, close, statement, statementSpace, ifNot, forIn, iterVar, key, newlineAfter, offset, s) {
    if (escapeChar) return str.replace('\\\\', '');
    // if a logic tag is on a line by itself remove preceding newline and
    // whitespace
    if (newlineBefore && newlineAfter !== undefined) {
      newlineBefore = '';
    }
    // opening tags
    if (statement && statementSpace && key) {
      levels[statement]++;
      // {for foo in bar}
      if (statement === 'for' && iterVar) {
        return newlineBefore+'\';var '+iterVar+'A=g(\''+key+'\');for(var '+iterVar+'I=0;'+iterVar+'I<'+iterVar+'A.length;'+iterVar+'I++){c[\''+iterVar+'\']='+iterVar+'A['+iterVar+'I];b+=\'';
      }
      // {if foo} or {if not foo}
      if (statement === 'if') {
        return newlineBefore+'\';if('+(ifNot?'!':'')+'g(\''+key+'\')){b+=\'';
      }
    }
    // closing tags ({/for} or {/if})
    if (close && statement) {
      if (levels[statement] === 0) {
        console.warn('extra {/'+statement+'} ignored');
        return '';
      } else {
        levels[statement]--;
        return newlineBefore+'\';}b+=\'';
      }
    }
    // not a tag, don't replace
    return str;
  });

  // close extra fors and ifs
  for (statement in levels) {
    for (var i=0; i<levels[statement]; i++) {
      console.warn('extra "'+statement+'" closed at end of template');
      template = template+'\';}b+=\'';
    }
  }

  // escape newlines for eval
  template = template.replace(/\n/g, '\\n');

  // wrap in function and return
  // c is context, b is buffer, g is get, v is value, k is key
  return '(function(){return function(c){var g=function(k){var v;try{v=eval(\'c.\'+k)||\'\'}catch(e){v=\'\'}if(typeof v==\'function\')v=v(c);return v;};var b=\''+template+'\';return b}})()';
};

// main function for rendering templates
whiskers.render = function(template, context, partials) {
  template = whiskers.expand(template, partials);
  // use cached if it exists
  if (whiskers.cache[template]) return whiskers.cache[template](context);
  // compile and cache
  whiskers.cache[template] = eval(whiskers.compile(template));
  return whiskers.cache[template](context);
};

// commonjs
if (typeof module === 'object') {
  module.exports = whiskers;
}
<|endoftext|>