<commit_before>import { selectValueByKey, selectData, selectMeta } from './'
import { selectItems } from './collection'
import get from 'lodash.get'

// payload: { type, id, key, options }
export const selectItem = (state) => (payload) => {
  const { type, id, options } = payload
  const items = selectItems(state)(payload)
  if (!Array.isArray(items)) { return undefined }
  if (!id && options) {
    const { slug } = options
    return items.find(item => {
      const value = selectRawAttributeByName(item)('slug')
      return value === slug
    })
  }
  return items.find(item => item.type === type && item.id === id)
}

export const selectItemIsLoading = state => payload => {
  const item = selectItem(state)(payload)
  const meta = selectMeta(item)
  return selectValueByKey(meta)('isLoading')
}

export const selectItemIsLoaded = state => payload => {
  const item = selectItem(state)(payload)
  const meta = selectMeta(item)
  return selectValueByKey(meta)('IsLoaded')
}

export const selectItemAttribute = state => payload => {
  const item = selectItem(state)(payload)
  const { key } = payload
  return selectAttribute(item)(key)
}

export const selectAttribute = item => key => {
  const attributes = selectAttributes(item)
  return get(attributes, key)
}

export const selectItemMetaKey = state => payload => {
  const item = selectItem(state)(payload)
  const { key } = payload
  return selectMetaKey(item)(key)
}

export const selectMetaKey = item => key => {
  const meta = selectMeta(item)
  return get(meta, key)
}

// --- older, may not be as useful

export const selectItemById = (state) => (type, id) => {
  const items = selectItems(state)({ type })
  if (!Array.isArray(items)) { return undefined }
  return items.find(item => item.type === type && item.id === id)
}

export const selectRawItemAttributes = (state) => (type, id) => {
  const item = selectItemById(state)(type, id)
  return selectRawAttributes(item)
}

export const selectRawAttributes = (item) => selectValueByKey(item)('attributes')

export const selectItemChangedAttributes = (state) => (type, id) => {
  const item = selectItemById(state)(type, id)
  return selectChangedAttributes(item)
}

export const selectChangedAttributes = (item) => {
  const meta = selectMeta(item)
  return selectValueByKey(meta)('changedAttributes')
}

export const selectItemAttributes = (state) => (type, id) => {
  const item = selectItemById(state)(type, id)
  return selectAttributes(item)
}

export const selectAttributes = (item) => {
  const rawAttributes = selectRawAttributes(item)
  const changedAttributes = selectChangedAttributes(item)
  return { ...rawAttributes, ...changedAttributes }
}

export const selectItemAttributeByName = (state) => (type, id, name) => {
  const item = selectItemById(state)(type, id)
  return selectAttributeByName(item)(name)
}

export const selectAttributeByName = (item) => (name) => {
  const attributes = selectAttributes(item)
  return selectValueByKey(attributes)(name)
}

export const selectItemRawAttributeByName = (state) => (type, id, name) => {
  const item = selectItemById(state)(type, id)
  return selectRawAttributeByName(item)(name)
}

export const selectRawAttributeByName = (item) => (name) => {
  const attributes = selectRawAttributes(item)
  return selectValueByKey(attributes)(name)
}

export const selectItemChangedAttributeByName = (state) => (type, id, name) => {
  const item = selectItemById(state)(type, id)
  return selectChangedAttributeByName(item)(name)
}

export const selectChangedAttributeByName = (item) => (name) => {
  const attributes = selectChangedAttributes(item)
  return selectValueByKey(attributes)(name)
}

export const selectItemRelationships = (state) => (type, id) => {
  const item = selectItemById(state)(type, id)
  return selectRelationships(item)
}

// TODO: mofe to ./relationships
export const selectRelationships = (item) => {
  return selectValueByKey(item)('relationships')
}

export const selectItemRelationshipByName = (state) => (type, id, name) => {
  const relationships = selectItemRelationships(state)(type, id)
  return selectRelationshipByName(relationships)(name)
}

export const selectRelationshipByName = (relationships) => (name) => selectValueByKey(relationships)(name)

export const selectRelationshipDataByName = (relationships) => (name) => {
  const relationship = selectRelationshipByName(relationships)(name)
  return selectRelationshipData(relationship)
}

export const selectRelationshipRawDataByName = (relationships) => (name) => {
  const relationship = selectRelationshipByName(relationships)(name)
  return selectRelationshipRawData(relationship)
}

export const selectRelationshipChangeDataByName = (relationships) => (name) => {
  const relationship = selectRelationshipByName(relationships)(name)
  return selectRelationshipChangedData(relationship)
}

export const selectRelationshipData = (relationship) => {
  const data = selectData(relationship)
  const meta = selectMeta(relationship)
  const changedData = selectValueByKey(meta)('changedData')
  return changedData || data
}

export const selectRelationshipRawData = (relationship) => selectData(relationship)

export const selectRelationshipChangedData = (relationship) => {
  const meta = selectMeta(relationship)
  return selectValueByKey(meta)('changedData')
}
<commit_msg>select item by attribute<commit_after>import { selectValueByKey, selectData, selectMeta } from './'
import { selectItems } from './collection'
import get from 'lodash.get'

// payload: { type, id, key, options }
export const selectItem = state => payload => {
  const { type, id, options } = payload
  const items = selectItems(state)(payload)
  if (!Array.isArray(items)) { return undefined }
  if (!id && options) {
    const { slug } = options
    return items.find(item => {
      const value = selectRawAttributeByName(item)('slug')
      return value === slug
    })
  }
  return items.find(item => item.type === type && item.id === id)
}

// payload: { type, key, value}
export const selectItemByAttribute = state => payload => {
  const { type, key, value } = payload
  const items = selectItems(state)({ type })
  return items.find(item => {
    const attribute = selectAttribute(item)(key)
    return attribute === value
  })
}

export const selectItemIsLoading = state => payload => {
  const item = selectItem(state)(payload)
  const meta = selectMeta(item)
  return selectValueByKey(meta)('isLoading')
}

export const selectItemIsLoaded = state => payload => {
  const item = selectItem(state)(payload)
  const meta = selectMeta(item)
  return selectValueByKey(meta)('IsLoaded')
}

export const selectItemAttribute = state => payload => {
  const item = selectItem(state)(payload)
  const { key } = payload
  return selectAttribute(item)(key)
}

export const selectAttribute = item => key => {
  const attributes = selectAttributes(item)
  return get(attributes, key)
}

export const selectItemMetaKey = state => payload => {
  const item = selectItem(state)(payload)
  const { key } = payload
  return selectMetaKey(item)(key)
}

export const selectMetaKey = item => key => {
  const meta = selectMeta(item)
  return get(meta, key)
}

// --- older, may not be as useful

export const selectItemById = (state) => (type, id) => {
  const items = selectItems(state)({ type })
  if (!Array.isArray(items)) { return undefined }
  return items.find(item => item.type === type && item.id === id)
}

export const selectRawItemAttributes = (state) => (type, id) => {
  const item = selectItemById(state)(type, id)
  return selectRawAttributes(item)
}

export const selectRawAttributes = (item) => selectValueByKey(item)('attributes')

export const selectItemChangedAttributes = (state) => (type, id) => {
  const item = selectItemById(state)(type, id)
  return selectChangedAttributes(item)
}

export const selectChangedAttributes = (item) => {
  const meta = selectMeta(item)
  return selectValueByKey(meta)('changedAttributes')
}

export const selectItemAttributes = (state) => (type, id) => {
  const item = selectItemById(state)(type, id)
  return selectAttributes(item)
}

export const selectAttributes = (item) => {
  const rawAttributes = selectRawAttributes(item)
  const changedAttributes = selectChangedAttributes(item)
  return { ...rawAttributes, ...changedAttributes }
}

export const selectItemAttributeByName = (state) => (type, id, name) => {
  const item = selectItemById(state)(type, id)
  return selectAttributeByName(item)(name)
}

export const selectAttributeByName = (item) => (name) => {
  const attributes = selectAttributes(item)
  return selectValueByKey(attributes)(name)
}

export const selectItemRawAttributeByName = (state) => (type, id, name) => {
  const item = selectItemById(state)(type, id)
  return selectRawAttributeByName(item)(name)
}

export const selectRawAttributeByName = (item) => (name) => {
  const attributes = selectRawAttributes(item)
  return selectValueByKey(attributes)(name)
}

export const selectItemChangedAttributeByName = (state) => (type, id, name) => {
  const item = selectItemById(state)(type, id)
  return selectChangedAttributeByName(item)(name)
}

export const selectChangedAttributeByName = (item) => (name) => {
  const attributes = selectChangedAttributes(item)
  return selectValueByKey(attributes)(name)
}

export const selectItemRelationships = (state) => (type, id) => {
  const item = selectItemById(state)(type, id)
  return selectRelationships(item)
}

// TODO: mofe to ./relationships
export const selectRelationships = (item) => {
  return selectValueByKey(item)('relationships')
}

export const selectItemRelationshipByName = (state) => (type, id, name) => {
  const relationships = selectItemRelationships(state)(type, id)
  return selectRelationshipByName(relationships)(name)
}

export const selectRelationshipByName = (relationships) => (name) => selectValueByKey(relationships)(name)

export const selectRelationshipDataByName = (relationships) => (name) => {
  const relationship = selectRelationshipByName(relationships)(name)
  return selectRelationshipData(relationship)
}

export const selectRelationshipRawDataByName = (relationships) => (name) => {
  const relationship = selectRelationshipByName(relationships)(name)
  return selectRelationshipRawData(relationship)
}

export const selectRelationshipChangeDataByName = (relationships) => (name) => {
  const relationship = selectRelationshipByName(relationships)(name)
  return selectRelationshipChangedData(relationship)
}

export const selectRelationshipData = (relationship) => {
  const data = selectData(relationship)
  const meta = selectMeta(relationship)
  const changedData = selectValueByKey(meta)('changedData')
  return changedData || data
}

export const selectRelationshipRawData = (relationship) => selectData(relationship)

export const selectRelationshipChangedData = (relationship) => {
  const meta = selectMeta(relationship)
  return selectValueByKey(meta)('changedData')
}
<|endoftext|>


<commit_before>/*
    Title: Example Server

    An example implementation of a <Game Controller at http://fluencychallenge.com/wiki/DesignAndImplementation/GameController> which serves a website and allows users to play through several static sequences of problems from a choice of game engines.
*/

var http = require('http'),
    urllib = require('url'),
    express = require('express'),
    GameController = require('../common/GameController').GameController,
    PlayerState = require('../common/PlayerState').PlayerState,
    exampleGames = require('./exampleGames');

function runServer(port, rootPath)
{
    // Create our simple GameController instance that doesn't keep any player state info, and returns our static set of stages.
    var gc = new GameController();
    gc.getPlayerState = function (playerID, authentication, callback)
    {
        setTimeout(callback, 0, new PlayerState(playerID));
    }
    gc.getStage = function (stageID, callback)
    {
        for (var i = 0; i < exampleGames.stages.length; i++)
        {
            if (exampleGames.stages[i].id == stageID)
            {
                setTimeout(callback, 0, exampleGames.stages[i]);
                return;
            }
        }
    }
    gc.getAvailableStagesForPlayer = function (playerState, callback)
    {
        // playerState is ignored since everyone sees the same static stages.
        setTimeout(callback, 0, exampleGames.stages);
    }
    gc.getGameEngineForQuestionSet = function (questionSet, callback)
    {
        var engineID = questionSet.allGameProperties().engineID;
        setTimeout(callback, 0, exampleGames.engines[engineID]);
    }

    // Create a simple server that presents a single HTML page and responds to AJAX API requests to launch the static games.
    var app = express.createServer();
    if (rootPath && rootPath != '/')
    {
        app.set('home', rootPath);
    }
    else
    {
        rootPath = '';
    }
    app.set('view options', {layout: false});

    app.use(express.bodyParser());
    app.configure('development', function ()
    {
        app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
        app.use(express.logger());
    });

    app.param('playerID', function (req, res, next, playerID)
    {
        gc.getPlayerState(playerID, null, function (playerState)
        {
            req.playerState = playerState;
            next();
        });
    });
    app.param('stageID', function (req, res, next, stageID)
    {
        gc.getStage(stageID, function (stage)
        {
            req.stage = stage;
            next();
        });
    });
    app.param('questionSetID', function (req, res, next, questionSetID)
    {
        req.stage.getQuestionSet(questionSetID, function (questionSet)
        {
            req.questionSet = questionSet;
            next();
        });
    });

    // Static handlers for client-side JS and game assessts, etc.
    app.use(rootPath + '/js/node_modules', express.static(__dirname + '/../../node_modules'));
    app.use(rootPath + '/js/common', express.static(__dirname + '/../common'));
    app.use(rootPath + '/js/client', express.static(__dirname + '/../client'));
    app.use(rootPath + '/static', express.static(__dirname + '/../static'));
    app.use(rootPath + '/static', express.directory(__dirname + '/../static'));

    // Dynamic handlers for index template -- require a trailing slash (redirect otherwise).
    app.get(new RegExp('^' + rootPath + '$'), function (req, res)
    {
        res.redirect(rootPath + '/');
    });
    app.get(new RegExp('^' + rootPath + '/(:?index\\.html)?$'), function (req, res)
    {
        res.render(__dirname + '/templates/example.ejs');
    });

    // Dynamic handlers for AJAX API.
    app.get(rootPath + '/stage/:stageID?', function (req, res)
    {
        if (req.stage)
        {
            res.send(req.stage.toJSON());
        }
        else
        {
            gc.getAvailableStagesForPlayer(req.playerState, function (stages)
            {
                res.send({'stageIDs': stages.map(function (stage)
                {
                    return stage.id;
                })});
            });
        }
    });
    app.get(rootPath + '/stage/:stageID/questionSet/:questionSetID/engine', function (req, res)
    {
        var questionSet = req.stage;
        gc.getGameEngineForQuestionSet(req.questionSet, function (engine)
        {
            res.send(engine.toJSON());
        });
    });

    // Start the server.
    app.listen(8000);
    console.log('Server running on port ' + port);
}

if (require.main === module) runServer(8000, '/fluencydemo');
<commit_msg>Pass port and rootPath from command line.<commit_after>/*
    Title: Example Server

    An example implementation of a <Game Controller at http://fluencychallenge.com/wiki/DesignAndImplementation/GameController> which serves a website and allows users to play through several static sequences of problems from a choice of game engines.
*/

var http = require('http'),
    urllib = require('url'),
    express = require('express'),
    GameController = require('../common/GameController').GameController,
    PlayerState = require('../common/PlayerState').PlayerState,
    exampleGames = require('./exampleGames');

function runServer(port, rootPath)
{
    // Create our simple GameController instance that doesn't keep any player state info, and returns our static set of stages.
    var gc = new GameController();
    gc.getPlayerState = function (playerID, authentication, callback)
    {
        setTimeout(callback, 0, new PlayerState(playerID));
    }
    gc.getStage = function (stageID, callback)
    {
        for (var i = 0; i < exampleGames.stages.length; i++)
        {
            if (exampleGames.stages[i].id == stageID)
            {
                setTimeout(callback, 0, exampleGames.stages[i]);
                return;
            }
        }
    }
    gc.getAvailableStagesForPlayer = function (playerState, callback)
    {
        // playerState is ignored since everyone sees the same static stages.
        setTimeout(callback, 0, exampleGames.stages);
    }
    gc.getGameEngineForQuestionSet = function (questionSet, callback)
    {
        var engineID = questionSet.allGameProperties().engineID;
        setTimeout(callback, 0, exampleGames.engines[engineID]);
    }

    // Create a simple server that presents a single HTML page and responds to AJAX API requests to launch the static games.
    var app = express.createServer();
    if (rootPath && rootPath != '/')
    {
        app.set('home', rootPath);
    }
    else
    {
        rootPath = '';
    }
    app.set('view options', {layout: false});

    app.use(express.bodyParser());
    app.configure('development', function ()
    {
        app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
        app.use(express.logger());
    });

    app.param('playerID', function (req, res, next, playerID)
    {
        gc.getPlayerState(playerID, null, function (playerState)
        {
            req.playerState = playerState;
            next();
        });
    });
    app.param('stageID', function (req, res, next, stageID)
    {
        gc.getStage(stageID, function (stage)
        {
            req.stage = stage;
            next();
        });
    });
    app.param('questionSetID', function (req, res, next, questionSetID)
    {
        req.stage.getQuestionSet(questionSetID, function (questionSet)
        {
            req.questionSet = questionSet;
            next();
        });
    });

    // Static handlers for client-side JS and game assessts, etc.
    app.use(rootPath + '/js/node_modules', express.static(__dirname + '/../../node_modules'));
    app.use(rootPath + '/js/common', express.static(__dirname + '/../common'));
    app.use(rootPath + '/js/client', express.static(__dirname + '/../client'));
    app.use(rootPath + '/static', express.static(__dirname + '/../static'));
    app.use(rootPath + '/static', express.directory(__dirname + '/../static'));

    // Dynamic handlers for index template -- require a trailing slash (redirect otherwise).
    app.get(new RegExp('^' + rootPath + '$'), function (req, res)
    {
        res.redirect(rootPath + '/');
    });
    app.get(new RegExp('^' + rootPath + '/(:?index\\.html)?$'), function (req, res)
    {
        res.render(__dirname + '/templates/example.ejs');
    });

    // Dynamic handlers for AJAX API.
    app.get(rootPath + '/stage/:stageID?', function (req, res)
    {
        if (req.stage)
        {
            res.send(req.stage.toJSON());
        }
        else
        {
            gc.getAvailableStagesForPlayer(req.playerState, function (stages)
            {
                res.send({'stageIDs': stages.map(function (stage)
                {
                    return stage.id;
                })});
            });
        }
    });
    app.get(rootPath + '/stage/:stageID/questionSet/:questionSetID/engine', function (req, res)
    {
        var questionSet = req.stage;
        gc.getGameEngineForQuestionSet(req.questionSet, function (engine)
        {
            res.send(engine.toJSON());
        });
    });

    // Start the server.
    app.listen(port);
    console.log('Server running on port ' + port + ' with URL root ' + rootPath);
}

if (require.main === module)
{
    if (process.argv.length != 4)
    {
        console.log('Invalid argument(s).');
        console.log('Usage: node example.js PORT ROOT');
        console.log('PORT is the server port (e.g. 80)');
        console.log('ROOT is the server URL root path (e.g. "/fluencydemo")');
        process.exit(1);
    }
    var port = parseInt(process.argv[2]);
    var root = process.argv[3];
    runServer(port, root);
}
<|endoftext|>


<commit_before>var GameController = function(args) {
  this.pelletCount = 0;
  this.lives = 2;
  this.keyStates = {
    up: false,
    down: false,
    left: false,
    right: false
  }
  this.pacMoveInterval = false;

  this.pacCanvas = args.pacCanvas;
  this.blinkyCanvas = args.blinkyCanvas;
  this.inkyCanvas = args.inkyCanvas;
  this.pinkyCanvas = args.pinkyCanvas;
  this.clydeCanvas = args.clydeCanvas;
  this.boardCanvas = args.boardCanvas;
  this.pelletCanvas = args.pelletCanvas;

  this.resetActors();

  this.gameBoard = args.gameBoard;
  this.actorBoard = args.actorBoard;

  this.drawPellets();

  this.pacCanvas.renderPac(this.pac);
  this.updateGameBoard();

  addEventListener("keydown", this.handleKeyDown.bind(this));
  addEventListener("keyup", this.handleKeyUp.bind(this));

  setInterval(function() {
    this.moveGhost("b");
    this.moveGhost("i");
    this.moveGhost("p");
    this.moveGhost("c");
  }.bind(this), GHOST_MOVE_DELAY);

  setTimeout(function() {
    this.ghostsMode = "chase";
  }.bind(this), 7000);
}
GameController.prototype.resetActors = function() {
  for(var prop in ACTOR_ARGS) {
    if(ACTOR_ARGS.hasOwnProperty(prop)) {
      if(prop == "pac") {
        this.pac = new Actor(ACTOR_ARGS.pac);
      }
      else {
        this[prop] = new Ghost(ACTOR_ARGS[prop]);
      }
    }
  }
};
GameController.prototype.drawPellets = function() {
  this.pelletCanvas.clearRect({
    x: 0,
    y: 0,
    w: BOARD_WIDTH,
    h: BOARD_HEIGHT
  });
  this.gameBoard.board.matrix.forEach(function(row, rIndex) {
    row.forEach(function(col, cIndex) {
      if(col == ".") {
        this.pelletCanvas.drawRect({
          color: PELLET_COLOR,
          x: (8 * cIndex) + 3,
          y: (8 * rIndex) + 27,
          w: 2,
          h: 2
        });
      }
      else if(col == "o") {
        this.pelletCanvas.drawCircle({
          x: (8 * cIndex) + 4,
          y: (8 * rIndex) + 28,
          rad: 4
        });
      }
      else if(col == "-") {
        this.pelletCanvas.drawRect({
          color: PELLET_COLOR,
          x: 8 * cIndex,
          y: (8 * rIndex) + 29,
          w: 8,
          h: 2
        });
      }
    }.bind(this));
  }.bind(this));
};
GameController.prototype.moveActor = function() {
  this.pacCanvas.clearRect(this.pac.getClearDimensions());
  var coords = {
    x: this.pac.x,
    y: this.pac.y
  }

  var newDirection = false;
  for(var prop in this.keyStates) {
    if(this.keyStates.hasOwnProperty(prop) && this.keyStates[prop]) {
      newDirection = prop;
      break;
    }
  }

  var collision;
  if(this.keyStates[this.pac.direction] === false && newDirection) {
    collision = this.gameBoard.predictCollision(coords, newDirection);
    if(collision != "door" && collision != "wall") {
      this.pac.direction = newDirection;
    }
  }

  collision = this.gameBoard.predictCollision(coords, this.pac.direction);
  if(collision == "wall" || collision == "door") {
    clearInterval(this.pacMoveInterval);
    this.pacMoveInterval = false;
  }
  else {
    var coords = this.actorBoard.find("m");

    this.pac.move();
    if(this.pac.x < 0) {
      this.pac.x = BOARD_WIDTH;
    }
    else if(this.pac.x > BOARD_WIDTH) {
      this.pac.x = 0;
    }

    var newCoords = Board.convertToTile({
      x: this.pac.x,
      y: this.pac.y
    });

    this.updateActorBoard({
      coords: coords,
      newCoords: newCoords,
      name: "m",
      actor: "pac"
    });
  }
  this.pac.moveTowardCenter();
  this.updateGameBoard();

  this.pacCanvas.renderPac(this.pac);
};
GameController.prototype.moveGhost = function(name) {
  var ghost;
  switch(name) {
    case "b": ghost = "blinky"; break;
    case "i": ghost = "inky"; break;
    case "p": ghost = "pinky"; break;
    case "c": ghost = "clyde"; break;
  }
  this[ghost + "Canvas"].clearRect(this[ghost].getClearDimensions());

  switch(this[ghost].movementMode) {
    case "house":
      if(this[ghost].y + 8 >= HOUSE_BOTTOM || this[ghost].y - 5 <= HOUSE_TOP) {
        this[ghost].direction = oppositeDirection(this[ghost].direction);
      }
    break;
    case "exitting":
      this[ghost].exitHouse();
      if(this[ghost].movementMode == "scatter") {
        this.setNextDirection(ghost);
      }
    break;
    case "scatter":
      if(this[ghost].isCentered()) {
        this.setNextDirection(ghost);
      }
    break;
    case "chase":
      var coords = Board.convertToTile({
        x: this.pac.x,
        y: this.pac.y
      });
      var ghostCoords = Board.convertToTile({
        x: this[ghost].x,
        y: this[ghost].y
      });
      var blinkyCoords = Board.convertToTile({
        x: this.blinky.x,
        y: this.blinky.y
      });
      this[ghost].targetTile = Ghost[ghost + "Target"]({
        coords: coords,
        direction: this.pac.direction,
        ghost: ghostCoords,
        blinky: blinkyCoords
      });
      if(this[ghost].isCentered()) {
        this.setNextDirection(ghost);
      }
    break;
  }

  this[ghost].move();
  if(this[ghost].x < 0) {
    this[ghost].x = BOARD_WIDTH;
  }
  else if(this[ghost].x > BOARD_WIDTH) {
    this[ghost].x = 0;
  }
  this[ghost + "Canvas"].renderGhost(this[ghost]);
};
GameController.prototype.handleKeyDown = function(event) {
  var keyPressed = keyCodes[event.keyCode];
  if(keyPressed) {
    event.preventDefault();
    if(this.keyStates[keyPressed] === false) {
      this.keyStates[keyPressed] = true;
      if(this.pacMoveInterval === false) {
        this.pacMoveInterval = setInterval(this.moveActor.bind(this), this.pac.speed);
      }
    }
  }
};
GameController.prototype.handleKeyUp = function(event) {
  var keyPressed = keyCodes[event.keyCode];
  if(keyPressed) {
    event.preventDefault();
    this.keyStates[keyPressed] = false;
  }
};
GameController.prototype.startPacDeath = function() {
  this.pac.mouthPos = 0;

  var runDeathLoop = function() {
    this.pacCanvas.renderPacDeath(this.pac);
    if(this.pac.mouthPos < 1) {
      this.pac.mouthPos += 0.1;
      setTimeout(runDeathLoop.bind(this), PAC_DEATH_DELAY);
    }
    else {
      this.pacCanvas.clearRect({
        x: this.pac.x - this.pac.radius,
        y: this.pac.y - this.pac.radius,
        w: 2 * this.pac.radius,
        h: 2 * this.pac.radius
      })
    }
  }.bind(this);

  runDeathLoop();
};
GameController.prototype.setNextDirection = function(ghost) {
  var currentTile = Board.convertToTile({
    x: this[ghost].x,
    y: this[ghost].y
  });
  var adjacentTiles = this.gameBoard.getAdjacentTiles({
    x: this[ghost].x,
    y: this[ghost].y
  });
  adjacentTiles[oppositeDirection(this[ghost].direction)] = undefined;

  var emptyTiles = this.gameBoard.getEmptyTiles(adjacentTiles);
  var nextTile = this.gameBoard.getClosestTile({
    tiles: emptyTiles,
    target: this[ghost].targetTile
  });

  if(nextTile) {
    if(nextTile.x < currentTile.x) {
      this[ghost].direction = "left";
    }
    else if(nextTile.x > currentTile.x) {
      this[ghost].direction = "right";
    }
    else if(nextTile.y < currentTile.y) {
      this[ghost].direction = "up";
    }
    else if(nextTile.y > currentTile.y) {
      this[ghost].direction = "down";
    }
  }

  if(this.ghostsMode == "chase" && this[ghost].movementMode == "scatter") {
    this[ghost].setMode("chase");
  }
};

GameController.prototype.updateActorBoard = function(args) {
  if(args.coords.x != args.newCoords.x || args.coords.y != args.newCoords.y) {
    this.actorBoard.setCell({
      x: args.coords.x,
      y: args.coords.y,
      value: " "
    });
    this.actorBoard.setCell({
      x: args.newCoords.x,
      y: args.newCoords.y,
      value: args.name
    });
  }
};
GameController.prototype.updateGameBoard = function() {
  this.updatePellets();
  BrowserView.drawBorders(this.boardCanvas.context);
  this.updateLivesDisplay();
};
GameController.prototype.updateLivesDisplay = function() {
  for(var i = 0; i < 2; i++) {
    this.boardCanvas.clearRect({
      x: (24 + (16 * i)) - this.pac.radius,
      y: BOARD_HEIGHT - (8 + this.pac.radius),
      w: 2 * this.pac.radius,
      h: 2 * this.pac.radius
    })
  }
  for(var i = 0; i < this.lives; i++) {
    this.boardCanvas.renderPac({
      color: nameToColor["m"],
      mouthPos: 0.2,
      direction: "left",
      x: 24 + (16 * i),
      y: BOARD_HEIGHT - 8,
      radius: this.pac.radius
    });
  }
};
GameController.prototype.updatePellets = function() {
  var coords = Board.convertToTile({
    x: this.pac.x,
    y: this.pac.y
  });
  var tile = this.gameBoard.getCell(coords);

  if(tile == "." || tile == "o") {
    this.gameBoard.setCell({
      x: coords.x,
      y: coords.y,
      value: " "
    });
    this.pelletCount++;
    if(this.inky.movementMode == "house") {
      this.inky.handlePelletCount(this.pelletCount);
    }
    if(this.clyde.movementMode == "house") {
      this.clyde.handlePelletCount(this.pelletCount);
    }
    this.drawPellets();
  }

  var score = this.pelletCount.toString();
  if(score.length == 1) {
    score = "0" + score;
  }
  this.boardCanvas.drawText({
    text: score,
    col: 7 - score.length,
    row: 1
  });
};
<commit_msg>Add GameController prop to store ghost movement interval<commit_after>var GameController = function(args) {
  this.pelletCount = 0;
  this.lives = 2;
  this.keyStates = {
    up: false,
    down: false,
    left: false,
    right: false
  }
  this.pacMoveInterval = false;

  this.pacCanvas = args.pacCanvas;
  this.blinkyCanvas = args.blinkyCanvas;
  this.inkyCanvas = args.inkyCanvas;
  this.pinkyCanvas = args.pinkyCanvas;
  this.clydeCanvas = args.clydeCanvas;
  this.boardCanvas = args.boardCanvas;
  this.pelletCanvas = args.pelletCanvas;

  this.resetActors();

  this.gameBoard = args.gameBoard;
  this.actorBoard = args.actorBoard;

  this.drawPellets();

  this.pacCanvas.renderPac(this.pac);
  this.updateGameBoard();

  addEventListener("keydown", this.handleKeyDown.bind(this));
  addEventListener("keyup", this.handleKeyUp.bind(this));

  this.ghostMoveInterval = setInterval(function() {
    this.moveGhost("b");
    this.moveGhost("i");
    this.moveGhost("p");
    this.moveGhost("c");
  }.bind(this), GHOST_MOVE_DELAY);

  setTimeout(function() {
    this.ghostsMode = "chase";
  }.bind(this), 7000);
}
GameController.prototype.resetActors = function() {
  for(var prop in ACTOR_ARGS) {
    if(ACTOR_ARGS.hasOwnProperty(prop)) {
      if(prop == "pac") {
        this.pac = new Actor(ACTOR_ARGS.pac);
      }
      else {
        this[prop] = new Ghost(ACTOR_ARGS[prop]);
      }
    }
  }
};
GameController.prototype.drawPellets = function() {
  this.pelletCanvas.clearRect({
    x: 0,
    y: 0,
    w: BOARD_WIDTH,
    h: BOARD_HEIGHT
  });
  this.gameBoard.board.matrix.forEach(function(row, rIndex) {
    row.forEach(function(col, cIndex) {
      if(col == ".") {
        this.pelletCanvas.drawRect({
          color: PELLET_COLOR,
          x: (8 * cIndex) + 3,
          y: (8 * rIndex) + 27,
          w: 2,
          h: 2
        });
      }
      else if(col == "o") {
        this.pelletCanvas.drawCircle({
          x: (8 * cIndex) + 4,
          y: (8 * rIndex) + 28,
          rad: 4
        });
      }
      else if(col == "-") {
        this.pelletCanvas.drawRect({
          color: PELLET_COLOR,
          x: 8 * cIndex,
          y: (8 * rIndex) + 29,
          w: 8,
          h: 2
        });
      }
    }.bind(this));
  }.bind(this));
};
GameController.prototype.moveActor = function() {
  this.pacCanvas.clearRect(this.pac.getClearDimensions());
  var coords = {
    x: this.pac.x,
    y: this.pac.y
  }

  var newDirection = false;
  for(var prop in this.keyStates) {
    if(this.keyStates.hasOwnProperty(prop) && this.keyStates[prop]) {
      newDirection = prop;
      break;
    }
  }

  var collision;
  if(this.keyStates[this.pac.direction] === false && newDirection) {
    collision = this.gameBoard.predictCollision(coords, newDirection);
    if(collision != "door" && collision != "wall") {
      this.pac.direction = newDirection;
    }
  }

  collision = this.gameBoard.predictCollision(coords, this.pac.direction);
  if(collision == "wall" || collision == "door") {
    clearInterval(this.pacMoveInterval);
    this.pacMoveInterval = false;
  }
  else {
    var coords = this.actorBoard.find("m");

    this.pac.move();
    if(this.pac.x < 0) {
      this.pac.x = BOARD_WIDTH;
    }
    else if(this.pac.x > BOARD_WIDTH) {
      this.pac.x = 0;
    }

    var newCoords = Board.convertToTile({
      x: this.pac.x,
      y: this.pac.y
    });

    this.updateActorBoard({
      coords: coords,
      newCoords: newCoords,
      name: "m",
      actor: "pac"
    });
  }
  this.pac.moveTowardCenter();
  this.updateGameBoard();

  this.pacCanvas.renderPac(this.pac);
};
GameController.prototype.moveGhost = function(name) {
  var ghost;
  switch(name) {
    case "b": ghost = "blinky"; break;
    case "i": ghost = "inky"; break;
    case "p": ghost = "pinky"; break;
    case "c": ghost = "clyde"; break;
  }
  this[ghost + "Canvas"].clearRect(this[ghost].getClearDimensions());

  switch(this[ghost].movementMode) {
    case "house":
      if(this[ghost].y + 8 >= HOUSE_BOTTOM || this[ghost].y - 5 <= HOUSE_TOP) {
        this[ghost].direction = oppositeDirection(this[ghost].direction);
      }
    break;
    case "exitting":
      this[ghost].exitHouse();
      if(this[ghost].movementMode == "scatter") {
        this.setNextDirection(ghost);
      }
    break;
    case "scatter":
      if(this[ghost].isCentered()) {
        this.setNextDirection(ghost);
      }
    break;
    case "chase":
      var coords = Board.convertToTile({
        x: this.pac.x,
        y: this.pac.y
      });
      var ghostCoords = Board.convertToTile({
        x: this[ghost].x,
        y: this[ghost].y
      });
      var blinkyCoords = Board.convertToTile({
        x: this.blinky.x,
        y: this.blinky.y
      });
      this[ghost].targetTile = Ghost[ghost + "Target"]({
        coords: coords,
        direction: this.pac.direction,
        ghost: ghostCoords,
        blinky: blinkyCoords
      });
      if(this[ghost].isCentered()) {
        this.setNextDirection(ghost);
      }
    break;
  }

  this[ghost].move();
  if(this[ghost].x < 0) {
    this[ghost].x = BOARD_WIDTH;
  }
  else if(this[ghost].x > BOARD_WIDTH) {
    this[ghost].x = 0;
  }
  this[ghost + "Canvas"].renderGhost(this[ghost]);
};
GameController.prototype.handleKeyDown = function(event) {
  var keyPressed = keyCodes[event.keyCode];
  if(keyPressed) {
    event.preventDefault();
    if(this.keyStates[keyPressed] === false) {
      this.keyStates[keyPressed] = true;
      if(this.pacMoveInterval === false) {
        this.pacMoveInterval = setInterval(this.moveActor.bind(this), this.pac.speed);
      }
    }
  }
};
GameController.prototype.handleKeyUp = function(event) {
  var keyPressed = keyCodes[event.keyCode];
  if(keyPressed) {
    event.preventDefault();
    this.keyStates[keyPressed] = false;
  }
};
GameController.prototype.startPacDeath = function() {
  this.pac.mouthPos = 0;

  var runDeathLoop = function() {
    this.pacCanvas.renderPacDeath(this.pac);
    if(this.pac.mouthPos < 1) {
      this.pac.mouthPos += 0.1;
      setTimeout(runDeathLoop.bind(this), PAC_DEATH_DELAY);
    }
    else {
      this.pacCanvas.clearRect({
        x: this.pac.x - this.pac.radius,
        y: this.pac.y - this.pac.radius,
        w: 2 * this.pac.radius,
        h: 2 * this.pac.radius
      })
    }
  }.bind(this);

  runDeathLoop();
};
GameController.prototype.setNextDirection = function(ghost) {
  var currentTile = Board.convertToTile({
    x: this[ghost].x,
    y: this[ghost].y
  });
  var adjacentTiles = this.gameBoard.getAdjacentTiles({
    x: this[ghost].x,
    y: this[ghost].y
  });
  adjacentTiles[oppositeDirection(this[ghost].direction)] = undefined;

  var emptyTiles = this.gameBoard.getEmptyTiles(adjacentTiles);
  var nextTile = this.gameBoard.getClosestTile({
    tiles: emptyTiles,
    target: this[ghost].targetTile
  });

  if(nextTile) {
    if(nextTile.x < currentTile.x) {
      this[ghost].direction = "left";
    }
    else if(nextTile.x > currentTile.x) {
      this[ghost].direction = "right";
    }
    else if(nextTile.y < currentTile.y) {
      this[ghost].direction = "up";
    }
    else if(nextTile.y > currentTile.y) {
      this[ghost].direction = "down";
    }
  }

  if(this.ghostsMode == "chase" && this[ghost].movementMode == "scatter") {
    this[ghost].setMode("chase");
  }
};

GameController.prototype.updateActorBoard = function(args) {
  if(args.coords.x != args.newCoords.x || args.coords.y != args.newCoords.y) {
    this.actorBoard.setCell({
      x: args.coords.x,
      y: args.coords.y,
      value: " "
    });
    this.actorBoard.setCell({
      x: args.newCoords.x,
      y: args.newCoords.y,
      value: args.name
    });
  }
};
GameController.prototype.updateGameBoard = function() {
  this.updatePellets();
  BrowserView.drawBorders(this.boardCanvas.context);
  this.updateLivesDisplay();
};
GameController.prototype.updateLivesDisplay = function() {
  for(var i = 0; i < 2; i++) {
    this.boardCanvas.clearRect({
      x: (24 + (16 * i)) - this.pac.radius,
      y: BOARD_HEIGHT - (8 + this.pac.radius),
      w: 2 * this.pac.radius,
      h: 2 * this.pac.radius
    })
  }
  for(var i = 0; i < this.lives; i++) {
    this.boardCanvas.renderPac({
      color: nameToColor["m"],
      mouthPos: 0.2,
      direction: "left",
      x: 24 + (16 * i),
      y: BOARD_HEIGHT - 8,
      radius: this.pac.radius
    });
  }
};
GameController.prototype.updatePellets = function() {
  var coords = Board.convertToTile({
    x: this.pac.x,
    y: this.pac.y
  });
  var tile = this.gameBoard.getCell(coords);

  if(tile == "." || tile == "o") {
    this.gameBoard.setCell({
      x: coords.x,
      y: coords.y,
      value: " "
    });
    this.pelletCount++;
    if(this.inky.movementMode == "house") {
      this.inky.handlePelletCount(this.pelletCount);
    }
    if(this.clyde.movementMode == "house") {
      this.clyde.handlePelletCount(this.pelletCount);
    }
    this.drawPellets();
  }

  var score = this.pelletCount.toString();
  if(score.length == 1) {
    score = "0" + score;
  }
  this.boardCanvas.drawText({
    text: score,
    col: 7 - score.length,
    row: 1
  });
};
<|endoftext|>


<commit_before>module.exports =
{
    "harvester" :
    {
        body : [WORK, CARRY, MOVE],
        behaviour : function (creep)
        {
            if(creep.carry.energy < creep.carryCapacity)
            {
            	var sources = creep.room.find(FIND_SOURCES);
            	creep.moveTo(sources[0]);
            	creep.harvest(sources[0]);
            }
            else
            {
            	creep.moveTo(Game.spawns.Spawn1);
            	creep.transferEnergy(Game.spawns.Spawn1)
            }
        }
    },

    "guard" :
    {
        body : [ATTACK, ATTACK, TOUGH, MOVE],
        behaviour : function (creep)
        {
            var targets = creep.room.find(FIND_HOSTILE_CREEPS).filter (function (creep) { return creep.owner.username != "Source Keeper" });
        	if(targets.length >= 1)
        	{
        		creep.moveTo(targets[0]);
        		creep.attack(targets[0]);
        	}
        }
    },

    "shooter" :
    {
        body : [RANGED_ATTACK, RANGED_ATTACK, ATTACK, TOUGH, MOVE],
        behaviour : function (creep)
        {
            var targets = creep.room.find(FIND_HOSTILE_CREEPS).filter (function (creep) { return creep.owner.username != "Source Keeper" });
        	if(targets.length >= 1)
        	{

        	    if (creep.pos.getRangeTo (targets[0].pos) > 3)
        	    {
        	       creep.moveTo(targets[0]);
        	    }

        		creep.rangedAttack(targets[0]);

        	}
        }
    },

    "upgrader" :
    {
        body : [WORK, WORK, CARRY, MOVE],
        behaviour : function (creep)
        {
            if(creep.carry.energy < creep.carryCapacity)
            {
                var spawn = Game.spawns.Spawn1
            	creep.moveTo (spawn)
                spawn.transferEnergy (creep);
            }
            else
            {
                var controller = creep.room.controller;
            	creep.moveTo(controller);
            	creep.upgradeController(controller)
            }
        }
    },

    "builder" :
    {
        body : [WORK, WORK, CARRY, MOVE],
        behaviour : function (creep)
        {
            var spawn =  Game.spawns.Spawn1
            if (creep.carry.energy == 0)
            {
                creep.moveTo (spawn)
                spawn.transferEnergy (creep)
            }
            else
            {
                var targets = creep.room.find(FIND_CONSTRUCTION_SITES);
        		if(targets.length)
        		{
        			creep.moveTo(targets[0]);
        		    creep.build(targets[0]);
        		}
            }
        }
    },

    "healer" :
    {
        body : [HEAL, MOVE],
        behaviour : function (creep)
        {
            // Creeps with health less then maximum
            var targets = creep.room.find(FIND_MY_CREEPS).filter (function (creep) {return creep.hitsMax > creep.hits});
        	if(targets.length >= 1)
        	{
        		creep.moveTo(targets[0]);
        		creep.heal(targets[0]);
        	}
        }
    }
}<commit_msg>remove obsolete parts from roles.js<commit_after>module.exports =
{
    "harvester" :
    {
        behaviour : function (creep)
        {
            if(creep.carry.energy < creep.carryCapacity)
            {
            	var sources = creep.room.find(FIND_SOURCES);
            	creep.moveTo(sources[0]);
            	creep.harvest(sources[0]);
            }
            else
            {
            	creep.moveTo(Game.spawns.Spawn1);
            	creep.transferEnergy(Game.spawns.Spawn1)
            }
        }
    },

    "guard" :
    {
        behaviour : function (creep)
        {
            var targets = creep.room.find(FIND_HOSTILE_CREEPS).filter (function (creep) { return creep.owner.username != "Source Keeper" });
        	if(targets.length >= 1)
        	{
        		creep.moveTo(targets[0]);
        		creep.attack(targets[0]);
        	}
        }
    },

    "shooter" :
    {
        behaviour : function (creep)
        {
            var targets = creep.room.find(FIND_HOSTILE_CREEPS).filter (function (creep) { return creep.owner.username != "Source Keeper" });
        	if(targets.length >= 1)
        	{

        	    if (creep.pos.getRangeTo (targets[0].pos) > 3)
        	    {
        	       creep.moveTo(targets[0]);
        	    }

        		creep.rangedAttack(targets[0]);

        	}
        }
    },

    "upgrader" :
    {
        behaviour : function (creep)
        {
            if(creep.carry.energy < creep.carryCapacity)
            {
                var spawn = Game.spawns.Spawn1
            	creep.moveTo (spawn)
                spawn.transferEnergy (creep);
            }
            else
            {
                var controller = creep.room.controller;
            	creep.moveTo(controller);
            	creep.upgradeController(controller)
            }
        }
    },

    "builder" :
    {
        behaviour : function (creep)
        {
            var spawn =  Game.spawns.Spawn1
            if (creep.carry.energy == 0)
            {
                creep.moveTo (spawn)
                spawn.transferEnergy (creep)
            }
            else
            {
                var targets = creep.room.find(FIND_CONSTRUCTION_SITES);
        		if(targets.length)
        		{
        			creep.moveTo(targets[0]);
        		    creep.build(targets[0]);
        		}
            }
        }
    },

    "healer" :
    {
        behaviour : function (creep)
        {
            // Creeps with health less then maximum
            var targets = creep.room.find(FIND_MY_CREEPS).filter (function (creep) {return creep.hitsMax > creep.hits});
        	if(targets.length >= 1)
        	{
        		creep.moveTo(targets[0]);
        		creep.heal(targets[0]);
        	}
        }
    }
}<|endoftext|>


<commit_before>"use strict";
var CONF = require("./config/conf"),    //综合配置
    handle = require("./common/handle"),//文本文件的模板操作
    middleware = require("./filter/middleware"),//支持中间件
    modules = require("./common/modules"),//支持的插件配置
    filter = require('./filter/filter'),//支持前置过滤器
    querystring = require("querystring"),
    path = require('path'),
    zlib = require("zlib"),
    mime = require("mime"),    //MIME类型
    http = require("http"),
     url = require("url"),
      fs = require("fs"),
       _ = require("underscore");
var staticConf = CONF.staticconf,                //静态文件服务器配置
    mini = middleware.mini,
    cdn = middleware.cdn,
    version = 'f2e-server ' + require('../package.json').version,
    serverInfo = {needUpdate: false};        //服务器相关的一些参数。
exports.handle = handle;
exports.middleware = middleware;
exports.modules = modules;
exports.start = function(conf){
    var server = http.createServer(function (req, resp) { try{
        var host = (req.headers.host + ':80').split(':'),
            pathurl,
            hostConf = CONF[ host[0] ],
            root,
            agent;
        if( hostConf && (host[1] | 0) === (hostConf.port | 0) ){ //域名识别
            conf = hostConf;
        }else if( (host[1] | 0) === 80 ){
            conf = CONF.localhost;
        }
        conf.hostname = conf.host || req.headers.host;
        root = conf.root;
        if( typeof filter.execute(req,resp,conf) !== "undefined"){
            return false;   //有返回值的时候, 防止继续运行
        } //过滤器提前, 可以修改url
        try{pathurl = decodeURI(url.parse(req.url).pathname); }catch(e){ pathurl = req.url; }
        var pathname = root + pathurl;

        //包装request功能
        resp.data = req.data = querystring.parse( url.parse(req.url).query );
        resp.util = req.util = {
            version: version,
            mime: mime,
            conf: conf,
            host: host[0],
            staticServer: "http://" + (staticConf.host || (host[0] + ':' + staticConf.port)) + "/"
        };
        req.$ = {title: pathurl, fileList: [], needUpdate: serverInfo.needUpdate };
        resp.cdnPath = req.headers.host + req.url; // cdn 索引
        var DEBUG = req.data.debug === "true" || conf.debug; //DEBUG模式判断

        // 资源未找到时， 处理信息
        var other = function (_req, _resp, _handle, _conf, _pathurl){
            var m = modules.get( _pathurl.replace('/','') );
            if(m){
                m.execute(_req,_resp,_conf.root,_handle,_conf);
            }else if(_conf.agent && _conf.agent.get && (agent = _conf.agent.get(_pathurl, _req, _resp, _conf) ) ){   // 代理过滤
                require('./filter/agent').execute(_req,_resp,agent,_req.url);
            }else{
                _resp.writeHead(404, {"Content-Type": "text/html"});
                fs.readFile(_conf.notFound || '', function (err, data){
                    if(err){
                        if( _conf.notFound ){ console.trace(err); }
                        _resp.end( '
404
' );
                    }else{
                        _resp.end( data );
                    }
                });
            }
        };

        setTimeout( function(){
            try{    // 欢迎页面处理
                if( conf.welcome && fs.statSync(pathname).isDirectory() ){
                    pathname += '/' + conf.welcome;
                    resp.cdnPath = req.headers.host + pathname; // cdn 索引 需要修改
                }
            }catch(e){
                other(req, resp, handle, conf, pathurl);
                return;
            }
            resp.gzip = conf.gzip && mime.isTXT(pathname) && !req.data._build_; //构建阶段禁用

            fs.stat(pathname,function(error, stats){
                pathname = path.resolve(pathname);  // 正则化路径
                if (pathname.indexOf(root) !== 0) { // directory traversal
                    other(req, resp, handle, conf, pathurl);
                    return;
                }

                if(stats && stats.isFile()){  //如果url对应的资源文件存在，根据后缀名写入MIME类型
                    if( req.method === "POST" ){    // POST请求 添加target参数以后, 使用 upload 插件进行解析。
                        req.data.target = pathurl;
                        modules.get("upload").execute(req,resp,root,handle,conf);
                        return;
                    }

                    if( !conf.cdn || req.data._build_){    // cdn 禁用启用， 构建阶段禁用
                        cdn.disabled( host[0] );
                    }else{
                        cdn.enable( host[0] );
                        if( cdn.execute(req, resp, stats) ){
                            return;
                        }
                    }

                    var expires = new Date();
                    expires.setTime( expires.getTime() + (conf.expires || 0) );
                    var baseHeader = {
                        "Content-Type": mime.get(pathname),
                        "Content-Encoding": resp.gzip ? "gzip" : "utf-8",
                        "Expires": expires.toUTCString(),
                        "Server": version,
                        "Last-Modified": new Date( +stats.mtime ).toUTCString()
                    };
                    resp.writeHead(200, _.extend(baseHeader, conf.headers));

                    var rs = fs.createReadStream(pathname), s = '', dataArr = [], ware;
                    rs.on('error',function(err){
                        throw err;
                    }).on('data',function(d){
                        s += d;
                        dataArr.push(d);
                    });

                    if( conf.middleware && (req.data.middleware !== "false") && (ware = middleware.get(pathname)) ){  //中间件处理, MIME需要mime.type中修改
                        rs.on('end',function(){
                            ware(req,resp,s,pathname,DEBUG);
                        });
                    }else if( conf.handle && mime.isTXT(pathname) && !( /[\.\-]min\.(js|css)$/.test(pathurl) ) && req.data.handle !== "false" ){    //handle
                        rs.on('end',function(){
                            handle.execute(req,resp,root,s, mini ,DEBUG, conf);
                        });
                    }else{
                        if( resp.gzip ){
                            rs.on("end", function(){
                                var cdnBuf = Buffer.concat(dataArr, s.length );
                                cdn.set( resp, resp.gzip ? zlib.gzipSync(cdnBuf) : cdnBuf, +stats.mtime );
                            });
                            rs.pipe( zlib.createGzip() ).pipe(resp);
                        }else{
                            rs.pipe(resp);
                        }
                    }
                } else if(conf.fs_mod && stats && stats.isDirectory()){  //如果当前url被成功映射到服务器的文件夹，创建一段列表字符串写出
                    require('./filter/directory').execute(req,resp,root,pathname,pathurl,conf,DEBUG);
                } else{
                    other(req, resp, handle, conf, pathurl);
                }
            });
        }, req.data.delay | 0 );// 增加delay参数，使得所有GET请求可以动态延时
    }catch(err){
        console.trace(err.stack);
        resp.writeHead(500, {"Content-Type": "text/html"});
        resp.end( err.stack.toString().replace(/\n/g,"
") );
    }});
    server.maxConnections = conf.maxConnections;
    server.listen(conf.port);
    return server;
};
// 检测更新信息
try{
    require('./config/update').execute(serverInfo);
}catch(e){
    console.trace( e );
}
<commit_msg>fix a bug in path filtering<commit_after>"use strict";
var CONF = require("./config/conf"),    //综合配置
    handle = require("./common/handle"),//文本文件的模板操作
    middleware = require("./filter/middleware"),//支持中间件
    modules = require("./common/modules"),//支持的插件配置
    filter = require('./filter/filter'),//支持前置过滤器
    querystring = require("querystring"),
    path = require('path'),
    zlib = require("zlib"),
    mime = require("mime"),    //MIME类型
    http = require("http"),
     url = require("url"),
      fs = require("fs"),
       _ = require("underscore");
var staticConf = CONF.staticconf,                //静态文件服务器配置
    mini = middleware.mini,
    cdn = middleware.cdn,
    version = 'f2e-server ' + require('../package.json').version,
    serverInfo = {needUpdate: false};        //服务器相关的一些参数。
exports.handle = handle;
exports.middleware = middleware;
exports.modules = modules;
exports.start = function(conf){
    var server = http.createServer(function (req, resp) { try{
        var host = (req.headers.host + ':80').split(':'),
            pathurl,
            hostConf = CONF[ host[0] ],
            root,
            basePath,
            agent;
        if( hostConf && (host[1] | 0) === (hostConf.port | 0) ){ //域名识别
            conf = hostConf;
        }else if( (host[1] | 0) === 80 ){
            conf = CONF.localhost;
        }
        conf.hostname = conf.host || req.headers.host;
        root = conf.root;
        basePath = path.resolve(root);
        if( typeof filter.execute(req,resp,conf) !== "undefined"){
            return false;   //有返回值的时候, 防止继续运行
        } //过滤器提前, 可以修改url
        try{pathurl = decodeURI(url.parse(req.url).pathname); }catch(e){ pathurl = req.url; }
        var pathname = root + pathurl;

        //包装request功能
        resp.data = req.data = querystring.parse( url.parse(req.url).query );
        resp.util = req.util = {
            version: version,
            mime: mime,
            conf: conf,
            host: host[0],
            staticServer: "http://" + (staticConf.host || (host[0] + ':' + staticConf.port)) + "/"
        };
        req.$ = {title: pathurl, fileList: [], needUpdate: serverInfo.needUpdate };
        resp.cdnPath = req.headers.host + req.url; // cdn 索引
        var DEBUG = req.data.debug === "true" || conf.debug; //DEBUG模式判断

        // 资源未找到时， 处理信息
        var other = function (_req, _resp, _handle, _conf, _pathurl){
            var m = modules.get( _pathurl.replace('/','') );
            if(m && m.execute){
                m.execute(_req,_resp,_conf.root,_handle,_conf);
            }else if(_conf.agent && _conf.agent.get && (agent = _conf.agent.get(_pathurl, _req, _resp, _conf) ) ){   // 代理过滤
                require('./filter/agent').execute(_req,_resp,agent,_req.url);
            }else{
                _resp.writeHead(404, {"Content-Type": "text/html"});
                fs.readFile(_conf.notFound || '', function (err, data){
                    if(err){
                        if( _conf.notFound ){ console.trace(err); }
                        _resp.end( '
404
' );
                    }else{
                        _resp.end( data );
                    }
                });
            }
        };

        setTimeout( function(){
            try{    // 欢迎页面处理
                if( conf.welcome && fs.statSync(pathname).isDirectory() ){
                    pathname += '/' + conf.welcome;
                    resp.cdnPath = req.headers.host + pathname; // cdn 索引 需要修改
                }
            }catch(e){
                other(req, resp, handle, conf, pathurl);
                return;
            }
            resp.gzip = conf.gzip && mime.isTXT(pathname) && !req.data._build_; //构建阶段禁用

            fs.stat(pathname,function(error, stats){
                pathname = path.resolve(pathname);  // 正则化路径
                if (pathname.indexOf(basePath) !== 0) { // directory traversal
                    other(req, resp, handle, conf, pathurl);
                    return;
                }

                if(stats && stats.isFile()){  //如果url对应的资源文件存在，根据后缀名写入MIME类型
                    if( req.method === "POST" ){    // POST请求 添加target参数以后, 使用 upload 插件进行解析。
                        req.data.target = pathurl;
                        modules.get("upload").execute(req,resp,root,handle,conf);
                        return;
                    }

                    if( !conf.cdn || req.data._build_){    // cdn 禁用启用， 构建阶段禁用
                        cdn.disabled( host[0] );
                    }else{
                        cdn.enable( host[0] );
                        if( cdn.execute(req, resp, stats) ){
                            return;
                        }
                    }

                    var expires = new Date();
                    expires.setTime( expires.getTime() + (conf.expires || 0) );
                    var baseHeader = {
                        "Content-Type": mime.get(pathname),
                        "Content-Encoding": resp.gzip ? "gzip" : "utf-8",
                        "Expires": expires.toUTCString(),
                        "Server": version,
                        "Last-Modified": new Date( +stats.mtime ).toUTCString()
                    };
                    resp.writeHead(200, _.extend(baseHeader, conf.headers));

                    var rs = fs.createReadStream(pathname), s = '', dataArr = [], ware;
                    rs.on('error',function(err){
                        throw err;
                    }).on('data',function(d){
                        s += d;
                        dataArr.push(d);
                    });

                    if( conf.middleware && (req.data.middleware !== "false") && (ware = middleware.get(pathname)) ){  //中间件处理, MIME需要mime.type中修改
                        rs.on('end',function(){
                            ware(req,resp,s,pathname,DEBUG);
                        });
                    }else if( conf.handle && mime.isTXT(pathname) && !( /[\.\-]min\.(js|css)$/.test(pathurl) ) && req.data.handle !== "false" ){    //handle
                        rs.on('end',function(){
                            handle.execute(req,resp,root,s, mini ,DEBUG, conf);
                        });
                    }else{
                        if( resp.gzip ){
                            rs.on("end", function(){
                                var cdnBuf = Buffer.concat(dataArr, s.length );
                                cdn.set( resp, resp.gzip ? zlib.gzipSync(cdnBuf) : cdnBuf, +stats.mtime );
                            });
                            rs.pipe( zlib.createGzip() ).pipe(resp);
                        }else{
                            rs.pipe(resp);
                        }
                    }
                } else if(conf.fs_mod && stats && stats.isDirectory()){  //如果当前url被成功映射到服务器的文件夹，创建一段列表字符串写出
                    require('./filter/directory').execute(req,resp,root,pathname,pathurl,conf,DEBUG);
                } else{
                    other(req, resp, handle, conf, pathurl);
                }
            });
        }, req.data.delay | 0 );// 增加delay参数，使得所有GET请求可以动态延时
    }catch(err){
        console.trace(err.stack);
        resp.writeHead(500, {"Content-Type": "text/html"});
        resp.end( err.stack.toString().replace(/\n/g,"
") );
    }});
    server.maxConnections = conf.maxConnections;
    server.listen(conf.port);
    return server;
};
// 检测更新信息
try{
    require('./config/update').execute(serverInfo);
}catch(e){
    console.trace( e );
}
<|endoftext|>


<commit_before>
/**
 * Copyright 2013, 2016 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Modifications copyright (C) 2016 Sense Tecnic Systems, Inc.
 *
 **/

/**
 *
 * Node for setting up connection to FRED
 * Based on Node-RED core websocket node
 *
 */

var p = require('./package.json');

module.exports = function(RED) {
  "use strict";
  var ws = require("ws");
  var inspect = require("util").inspect;
  var FRED_UNAUTHORIZED_ERROR = 'unexpected server response (401)';

  // A node red node that is either a FRED client or server
  function FredEndpointNode(n) {
    RED.nodes.createNode(this,n);
    var node = this;

    // Store local copies of the node configuration (as defined in the .html)
    node.isServer = (n.type === 'fred-server');
    node.private = n.private || false;
    node.endpoint = n.endpoint;
    node.fredUsername = n.username;

    // note - credentials are not passed in with config
    node.fredAPIKey = node.credentials?node.credentials.apikey : null;

    node.wholemsg = (n.wholemsg === "true");

    node._inputNodes = [];    // collection of nodes that want to receive events
    node._clients = {};

    if (node.isServer) {
      if (node.private) {
        node.path = "__"+node.endpoint;
      } else {
        node.path = "/public/__"+node.endpoint;
      }
    } else {
      node.path = p.config.fredHost;    // change host in the package for testing
      if (!node.private) {
        node.path = node.path + "/public/" + node.fredUsername + "/__" + node.endpoint;
      } else {
        node.path = node.path + "/api/__" + node.endpoint;
      }
    }

    node.closing = false;
    node.unauthorized = false;

    function startconn() {    // Connect to remote endpoint
      var opts = {};

      if (node.fredUsername && node.fredAPIKey) {
        opts = {
          headers: {
            "X-Auth-User": node.fredUsername,
            "X-Auth-Key": node.fredAPIKey
          }
        };
      }
      var socket = new ws(node.path, opts);
      node.server = socket; // keep for closing
      handleConnection(socket);
    }

    function handleConnection(/*socket*/socket) {
      var id = (1+Math.random()*4294967295).toString(16);
      if (node.isServer) {
        node._clients[id] = socket;
        node.emit('opened',Object.keys(node._clients).length);
      }

      socket.on('open',function() {
        if (!node.isServer) {
          node.emit('opened','');
        }
      });
      socket.on('close',function() {
        if (node.isServer) {
          delete node._clients[id];
          node.emit('closed',Object.keys(node._clients).length);
        } else {
          node.emit('closed');
        }
        if (!node.closing && !node.isServer && !node.unauthorized) { // don't reconnect if server returns 401 unauthorized
          if (node.tout) {
            clearTimeout(node.tout);
          }
          node.emit('reconnecting');
          node.tout = setTimeout(function(){ startconn(); }, 3000); // try to reconnect every 3 secs... bit fast ?
        }
      });
      socket.on('message',function(data,flags) {
        node.handleEvent(id,socket,'message',data,flags);
      });
      socket.on('error', function(err) {
        node.emit('erro', err.message);

        if (!node.closing && !node.isServer && !node.unauthorized) {
          if (err.message === FRED_UNAUTHORIZED_ERROR) {
            node.unauthorized = true; // don't reconnect again if server returns 401 unauthorized
          }
          if (node.tout) {
            clearTimeout(node.tout);
          }
          node.emit('reconnecting');
          node.tout = setTimeout(function(){ startconn(); }, 3000); // try to reconnect every 3 secs... bit fast ?
        }
      });
    }

    // we need the fred username in order to proxy the web socket request, can't do anything without it
    if (!node.fredUsername) {
      node.error(RED._("fred.errors.missing-username"));
      return; // this will be caught in FredEndpointNode.prototype.broadcast and message will be shown on the node
    }

    if (node.isServer) {
      var path = RED.settings.httpNodeRoot || "/";
      path = path + (path.slice(-1) == "/" ? "":"/") + (node.path.charAt(0) == "/" ? node.path.substring(1) : node.path);

      // Workaround https://github.com/einaros/ws/pull/253
      // Listen for 'newListener' events from RED.server
      node._serverListeners = {};

      var storeListener = function(/*String*/event,/*function*/listener){
        if(event == "error" || event == "upgrade" || event == "listening"){
          node._serverListeners[event] = listener;
        }
      }

      RED.server.addListener('newListener',storeListener);

      // Create a WebSocket Server
      node.server = new ws.Server({
        server:RED.server,
        path:path,
        // Disable the deflate option due to this issue
        //  https://github.com/websockets/ws/pull/632
        // that is fixed in the 1.x release of the ws module
        // that we cannot currently pickup as it drops node 0.10 support
        perMessageDeflate: false
      });

      // Workaround https://github.com/einaros/ws/pull/253
      // Stop listening for new listener events
      RED.server.removeListener('newListener',storeListener);

      node.server.on('connection', handleConnection);
    }
    else {
      node.closing = false;
      startconn(); // start outbound connection
    }

    node.on("close", function() {
      // Workaround https://github.com/einaros/ws/pull/253
      // Remove listeners from RED.server
      if (node.isServer) {
        var listener = null;
        for (var event in node._serverListeners) {
          if (node._serverListeners.hasOwnProperty(event)) {
            listener = node._serverListeners[event];
            if (typeof listener === "function") {
              RED.server.removeListener(event,listener);
            }
          }
        }
        node._serverListeners = {};
        node.server.close();
        node._inputNodes = [];
      }
      else {
        node.closing = true;
        node.server.close();
        if (node.tout) {
          clearTimeout(node.tout);
        }
      }
    });
  }
  RED.nodes.registerType("fred-server",FredEndpointNode);

  RED.nodes.registerType("fred-client",FredEndpointNode, {
    credentials: {
      apikey: {type:"text"}
    }
  });

  FredEndpointNode.prototype.registerInputNode = function(/*Node*/handler) {
    this._inputNodes.push(handler);
  }

  FredEndpointNode.prototype.removeInputNode = function(/*Node*/handler) {
    this._inputNodes.forEach(function(node, i, inputNodes) {
      if (node === handler) {
        inputNodes.splice(i, 1);
      }
    });
  }

  FredEndpointNode.prototype.handleEvent = function(id,/*socket*/socket,/*String*/event,/*Object*/data,/*Object*/flags){
    var msg;
    if (this.wholemsg) {
      try {
        msg = JSON.parse(data);
      }
      catch(err) {
        msg = { payload:data };
      }
    } else {
      msg = {
        payload:data
      };
    }
    msg._session = {type:"websocket",id:id};
    for (var i = 0; i < this._inputNodes.length; i++) {
      this._inputNodes[i].send(msg);
    }
  }

  FredEndpointNode.prototype.broadcast = function(data) {
    try {
      if(this.isServer) {
        for (var i = 0; i < this.server.clients.length; i++) {
          this.server.clients[i].send(data);
        }
      }
      else {
        if (this.server) {
          this.server.send(data);
        } else {
          if (!this.fredUsername) {
            this.emit('erro', RED._("fred.errors.missing-username"));
          } else {
            this.emit('erro', RED._("fred.errors.connect-error"));
          }
        }
      }
    }
    catch(e) { // swallow any errors
      this.warn("ws:"+i+" : "+e);
    }
  }

  FredEndpointNode.prototype.reply = function(id,data) {
    var session = this._clients[id];
    if (session) {
      try {
        session.send(data);
      }
      catch(e) { // swallow any errors
      }
    }
  }

  function FredInNode(n) {
    RED.nodes.createNode(this,n);
    this.server = (n.client)?n.client:n.server;
    var node = this;
    this.serverConfig = RED.nodes.getNode(this.server);
    if (this.serverConfig) {
      this.serverConfig.registerInputNode(this);
      // TODO: nls
      this.serverConfig.on('opened', function(n) {
        node.status({fill:"green",shape:"dot",text:"connected "+n});
      });
      this.serverConfig.on('erro', function(err) {
        if (err) {
          node.error(RED._("fred.errors.connect-error")+inspect(err));
          node.status({fill:"red",shape:"ring",text:err});
        }
        else {
          node.status({fill:"red",shape:"ring",text:"error"});
        }
      });
      this.serverConfig.on('closed', function() {
        if (node.serverConfig && node.serverConfig.unauthorized) {
          node.status({fill: "red",shape:"dot",text:"unauthorized"});
        } else {
          node.status({fill:"red",shape:"ring",text:"disconnected"});
        }
      });
      this.serverConfig.on('reconnecting', function() {
        node.status({fill:"grey",shape:"ring",text:"reconnecting"});
      });
    } else {
      this.error(RED._("fred.errors.missing-conf"));
    }

    this.on('close', function() {
      node.serverConfig.removeInputNode(node);
    });

  }
  RED.nodes.registerType("fred in",FredInNode);

  function FredOutNode(n) {
    RED.nodes.createNode(this,n);
    var node = this;
    this.server = (n.client)?n.client:n.server;
    this.serverConfig = RED.nodes.getNode(this.server);

    if (!this.serverConfig) {
      this.error(RED._("fred.errors.missing-conf"));
    }
    else {
      // TODO: nls
      this.serverConfig.on('opened', function(n) {
        node.status({fill:"green",shape:"dot",text:"connected "+n});
      });
      this.serverConfig.on('erro', function(err) {
        if (err) {
          node.error(RED._("fred.errors.connect-error")+inspect(err));
          node.status({fill:"red",shape:"ring",text:err});
        }
        else {
          node.status({fill:"red",shape:"ring",text:"error"});
        }
      });
      this.serverConfig.on('closed', function() {
        if (node.serverConfig && node.serverConfig.unauthorized) {
          node.status({fill: "red",shape:"dot",text:"unauthorized"});
        } else {
          node.status({fill:"red",shape:"ring",text:"disconnected"});
        }
      });
      this.serverConfig.on('reconnecting', function() {
        console.log("CHECK2")
        node.status({fill:"grey",shape:"ring",text:"reconnecting"});
      });
    }
    this.on("input", function(msg) {
      var payload;
      if (this.serverConfig.wholemsg) {
        delete msg._session;
        payload = JSON.stringify(msg);
      } else if (msg.hasOwnProperty("payload")) {
        if (!Buffer.isBuffer(msg.payload)) { // if it's not a buffer make sure it's a string.
          payload = RED.util.ensureString(msg.payload);
        }
        else {
          payload = msg.payload;
        }
      }
      if (payload) {
        if (msg._session && msg._session.type == "websocket") {
          node.serverConfig.reply(msg._session.id,payload);
        } else {
          node.serverConfig.broadcast(payload,function(error){
            if (!!error) {
              node.warn(RED._("fred.errors.send-error")+inspect(error));
            }
          });
        }
      }
    });
  }
  RED.nodes.registerType("fred out",FredOutNode);
}
<commit_msg>minor fix for missing username error message<commit_after>
/**
 * Copyright 2013, 2016 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Modifications copyright (C) 2016 Sense Tecnic Systems, Inc.
 *
 **/

/**
 *
 * Node for setting up connection to FRED
 * Based on Node-RED core websocket node
 *
 */

var p = require('./package.json');

module.exports = function(RED) {
  "use strict";
  var ws = require("ws");
  var inspect = require("util").inspect;
  var FRED_UNAUTHORIZED_ERROR = 'unexpected server response (401)';

  // A node red node that is either a FRED client or server
  function FredEndpointNode(n) {
    RED.nodes.createNode(this,n);
    var node = this;

    // Store local copies of the node configuration (as defined in the .html)
    node.isServer = (n.type === 'fred-server');
    node.private = n.private || false;
    node.endpoint = n.endpoint;
    node.fredUsername = n.username;

    // note - credentials are not passed in with config
    node.fredAPIKey = node.credentials?node.credentials.apikey : null;

    node.wholemsg = (n.wholemsg === "true");

    node._inputNodes = [];    // collection of nodes that want to receive events
    node._clients = {};

    if (node.isServer) {
      if (node.private) {
        node.path = "__"+node.endpoint;
      } else {
        node.path = "/public/__"+node.endpoint;
      }
    } else {
      node.path = p.config.fredHost;    // change host in the package for testing
      if (!node.private) {
        node.path = node.path + "/public/" + node.fredUsername + "/__" + node.endpoint;
      } else {
        node.path = node.path + "/api/__" + node.endpoint;
      }
    }

    node.closing = false;
    node.unauthorized = false;

    function startconn() {    // Connect to remote endpoint
      var opts = {};

      if (node.fredUsername && node.fredAPIKey) {
        opts = {
          headers: {
            "X-Auth-User": node.fredUsername,
            "X-Auth-Key": node.fredAPIKey
          }
        };
      }
      var socket = new ws(node.path, opts);
      node.server = socket; // keep for closing
      handleConnection(socket);
    }

    function handleConnection(/*socket*/socket) {
      var id = (1+Math.random()*4294967295).toString(16);
      if (node.isServer) {
        node._clients[id] = socket;
        node.emit('opened',Object.keys(node._clients).length);
      }

      socket.on('open',function() {
        if (!node.isServer) {
          node.emit('opened','');
        }
      });
      socket.on('close',function() {
        if (node.isServer) {
          delete node._clients[id];
          node.emit('closed',Object.keys(node._clients).length);
        } else {
          node.emit('closed');
        }
        if (!node.closing && !node.isServer && !node.unauthorized) { // don't reconnect if server returns 401 unauthorized
          if (node.tout) {
            clearTimeout(node.tout);
          }
          node.emit('reconnecting');
          node.tout = setTimeout(function(){ startconn(); }, 3000); // try to reconnect every 3 secs... bit fast ?
        }
      });
      socket.on('message',function(data,flags) {
        node.handleEvent(id,socket,'message',data,flags);
      });
      socket.on('error', function(err) {
        node.emit('erro', err.message);

        if (!node.closing && !node.isServer && !node.unauthorized) {
          if (err.message === FRED_UNAUTHORIZED_ERROR) {
            node.unauthorized = true; // don't reconnect again if server returns 401 unauthorized
          }
          if (node.tout) {
            clearTimeout(node.tout);
          }
          node.emit('reconnecting');
          node.tout = setTimeout(function(){ startconn(); }, 3000); // try to reconnect every 3 secs... bit fast ?
        }
      });
    }

    // we need the fred username in order to proxy the web socket request, can't do anything without it
    if (!node.fredUsername) {
      node.error(RED._("fred.errors.missing-username"));
      return; // this will be caught in FredEndpointNode.prototype.broadcast and message will be shown on the node
    }

    if (node.isServer) {
      var path = RED.settings.httpNodeRoot || "/";
      path = path + (path.slice(-1) == "/" ? "":"/") + (node.path.charAt(0) == "/" ? node.path.substring(1) : node.path);

      // Workaround https://github.com/einaros/ws/pull/253
      // Listen for 'newListener' events from RED.server
      node._serverListeners = {};

      var storeListener = function(/*String*/event,/*function*/listener){
        if(event == "error" || event == "upgrade" || event == "listening"){
          node._serverListeners[event] = listener;
        }
      }

      RED.server.addListener('newListener',storeListener);

      // Create a WebSocket Server
      node.server = new ws.Server({
        server:RED.server,
        path:path,
        // Disable the deflate option due to this issue
        //  https://github.com/websockets/ws/pull/632
        // that is fixed in the 1.x release of the ws module
        // that we cannot currently pickup as it drops node 0.10 support
        perMessageDeflate: false
      });

      // Workaround https://github.com/einaros/ws/pull/253
      // Stop listening for new listener events
      RED.server.removeListener('newListener',storeListener);

      node.server.on('connection', handleConnection);
    }
    else {
      node.closing = false;
      startconn(); // start outbound connection
    }

    node.on("close", function() {
      // Workaround https://github.com/einaros/ws/pull/253
      // Remove listeners from RED.server
      if (node.isServer) {
        var listener = null;
        for (var event in node._serverListeners) {
          if (node._serverListeners.hasOwnProperty(event)) {
            listener = node._serverListeners[event];
            if (typeof listener === "function") {
              RED.server.removeListener(event,listener);
            }
          }
        }
        node._serverListeners = {};
        node.server.close();
        node._inputNodes = [];
      }
      else {
        node.closing = true;
        node.server.close();
        if (node.tout) {
          clearTimeout(node.tout);
        }
      }
    });
  }
  RED.nodes.registerType("fred-server",FredEndpointNode);

  RED.nodes.registerType("fred-client",FredEndpointNode, {
    credentials: {
      apikey: {type:"text"}
    }
  });

  FredEndpointNode.prototype.registerInputNode = function(/*Node*/handler) {
    this._inputNodes.push(handler);
  }

  FredEndpointNode.prototype.removeInputNode = function(/*Node*/handler) {
    this._inputNodes.forEach(function(node, i, inputNodes) {
      if (node === handler) {
        inputNodes.splice(i, 1);
      }
    });
  }

  FredEndpointNode.prototype.handleEvent = function(id,/*socket*/socket,/*String*/event,/*Object*/data,/*Object*/flags){
    var msg;
    if (this.wholemsg) {
      try {
        msg = JSON.parse(data);
      }
      catch(err) {
        msg = { payload:data };
      }
    } else {
      msg = {
        payload:data
      };
    }
    msg._session = {type:"websocket",id:id};
    for (var i = 0; i < this._inputNodes.length; i++) {
      this._inputNodes[i].send(msg);
    }
  }

  FredEndpointNode.prototype.broadcast = function(data) {
    try {
      if(this.isServer) {
        for (var i = 0; i < this.server.clients.length; i++) {
          this.server.clients[i].send(data);
        }
      }
      else {
        if (this.server) {
          this.server.send(data);
        } else {
          if (!this.fredUsername) {
            this.emit('erro', RED._("fred.errors.missing-username"));
          } else {
            this.emit('erro', RED._("fred.errors.connect-error"));
          }
        }
      }
    }
    catch(e) { // swallow any errors
      this.warn("ws:"+i+" : "+e);
    }
  }

  FredEndpointNode.prototype.reply = function(id,data) {
    var session = this._clients[id];
    if (session) {
      try {
        session.send(data);
      }
      catch(e) { // swallow any errors
      }
    }
  }

  function FredInNode(n) {
    RED.nodes.createNode(this,n);
    this.server = (n.client)?n.client:n.server;
    var node = this;
    this.serverConfig = RED.nodes.getNode(this.server);
    if (this.serverConfig) {
      this.serverConfig.registerInputNode(this);
      // TODO: nls
      this.serverConfig.on('opened', function(n) {
        node.status({fill:"green",shape:"dot",text:"connected "+n});
      });
      this.serverConfig.on('erro', function(err) {
        if (err) {
          node.error(RED._("fred.errors.connect-error")+inspect(err));
          node.status({fill:"red",shape:"ring",text:err});
        }
        else {
          node.status({fill:"red",shape:"ring",text:"error"});
        }
      });
      this.serverConfig.on('closed', function() {
        if (node.serverConfig && node.serverConfig.unauthorized) {
          node.status({fill: "red",shape:"dot",text:"unauthorized"});
        } else if (node.serverConfig && !node.serverConfig.username) {
          node.status({fill: "red",shape:"dot",text: RED._("fred.errors.missing-username")});
        } else {
          node.status({fill:"red",shape:"ring",text:"disconnected"});
        }
      });
      this.serverConfig.on('reconnecting', function() {
        node.status({fill:"grey",shape:"ring",text:"reconnecting"});
      });
    } else {
      this.error(RED._("fred.errors.missing-conf"));
    }

    this.on('close', function() {
      node.serverConfig.removeInputNode(node);
    });

  }
  RED.nodes.registerType("fred in",FredInNode);

  function FredOutNode(n) {
    RED.nodes.createNode(this,n);
    var node = this;
    this.server = (n.client)?n.client:n.server;
    this.serverConfig = RED.nodes.getNode(this.server);

    if (!this.serverConfig) {
      this.error(RED._("fred.errors.missing-conf"));
    }
    else {
      // TODO: nls
      this.serverConfig.on('opened', function(n) {
        node.status({fill:"green",shape:"dot",text:"connected "+n});
      });
      this.serverConfig.on('erro', function(err) {
        if (err) {
          node.error(RED._("fred.errors.connect-error")+inspect(err));
          node.status({fill:"red",shape:"ring",text:err});
        }
        else {
          node.status({fill:"red",shape:"ring",text:"error"});
        }
      });
      this.serverConfig.on('closed', function() {
        if (node.serverConfig && node.serverConfig.unauthorized) {
          node.status({fill: "red",shape:"dot",text:"unauthorized"});
        } else if (node.serverConfig && !node.serverConfig.username) {
          node.status({fill: "red",shape:"dot",text: RED._("fred.errors.missing-username")});
        } else {
          node.status({fill:"red",shape:"ring",text:"disconnected"});
        }
      });
      this.serverConfig.on('reconnecting', function() {
        console.log("CHECK2")
        node.status({fill:"grey",shape:"ring",text:"reconnecting"});
      });
    }
    this.on("input", function(msg) {
      var payload;
      if (this.serverConfig.wholemsg) {
        delete msg._session;
        payload = JSON.stringify(msg);
      } else if (msg.hasOwnProperty("payload")) {
        if (!Buffer.isBuffer(msg.payload)) { // if it's not a buffer make sure it's a string.
          payload = RED.util.ensureString(msg.payload);
        }
        else {
          payload = msg.payload;
        }
      }
      if (payload) {
        if (msg._session && msg._session.type == "websocket") {
          node.serverConfig.reply(msg._session.id,payload);
        } else {
          node.serverConfig.broadcast(payload,function(error){
            if (!!error) {
              node.warn(RED._("fred.errors.send-error")+inspect(error));
            }
          });
        }
      }
    });
  }
  RED.nodes.registerType("fred out",FredOutNode);
}
<|endoftext|>


<commit_before>'use strict';

var angular = require('angular');
var Stripe  = require('stripe');

describe('stripe: Service', function () {

  this.timeout(500);

  beforeEach(angular.mock.module(require('../')));

  var data, response, successMock, errorMock;
  beforeEach(function () {
    data = {};
    response = {};
    successMock = sinon.spy(function (data, callback) {
      $timeout(angular.bind(null, callback, 200, response));
    });
    errorMock = sinon.spy(function (data, callback) {
      $timeout(angular.bind(null, callback, 400, response));
    });
  });

  var stripe, $timeout;
  beforeEach(angular.mock.inject(function (_stripe_, _$timeout_) {
    stripe = _stripe_;
    $timeout = _$timeout_;
  }));

  var sandbox;
  beforeEach(function () {
    sandbox = sinon.sandbox.create();
  });

  afterEach(function () {
    sandbox.restore();
  });

  describe('card', function () {

    it('exposes helper methods', function () {
      expect(stripe.card.validateCardNumber).to.equal(Stripe.card.validateCardNumber);
      expect(stripe.card.validateExpiry).to.equal(Stripe.card.validateExpiry);
      expect(stripe.card.validateCVC).to.equal(Stripe.card.validateCVC);
      expect(stripe.card.cardType).to.equal(Stripe.card.cardType);
    });

    describe('#createToken', function () {

      it('calls the Stripe.js method with the data', function () {
        sandbox.stub(Stripe.card, 'createToken');
        stripe.card.createToken(data);
        expect(Stripe.card.createToken).to.have.been.calledWith(data);
      });

      it('resolves on success', function () {
        Stripe.card.createToken = successMock;
        var promise = stripe.card.createToken(data);
        $timeout.flush();
        expect(promise).to.eventually.equal(response);
      });

      it('rejects on error', function () {
        response.error = {};
        Stripe.card.createToken = errorMock;
        var promise = stripe.card.createToken();
        $timeout.flush();
        expect(promise).to.be.rejectedWith(response.error);
      });

    });

  });

  describe('bankAccount', function () {

    it('exposes helper methods', function () {
      expect(stripe.bankAccount.validateRoutingNumber).to.equal(Stripe.bankAccount.validateRoutingNumber);
      expect(stripe.bankAccount.validateAccountNumber).to.equal(Stripe.bankAccount.validateAccountNumber);
    });

    describe('#createToken', function () {

      it('calls the Stripe.js method with the data', function () {
        sandbox.stub(Stripe.bankAccount, 'createToken');
        stripe.bankAccount.createToken(data);
        expect(Stripe.bankAccount.createToken).to.have.been.calledWith(data);
      });

      it('resolves on success', function () {
        Stripe.bankAccount.createToken = successMock;
        var promise = stripe.bankAccount.createToken(data);
        $timeout.flush();
        expect(promise).to.eventually.equal(response);
      });

      it('rejects on error', function () {
        response.error = {
          code: 'invalid_expiry_year',
          message: 'Your card\'s expiration year is invalid.',
          param: 'exp_year',
          type: 'card_error'
        };
        Stripe.bankAccount.createToken = errorMock;
        var promise = stripe.bankAccount.createToken();
        expect(promise).to.be.rejected
          .then(function (err) {
            expect(err).to.contain(response.error)
          });
        $timeout.flush();
      });

    });

  });

});
<commit_msg>Clean up tests<commit_after>'use strict';

var angular = require('angular');
var Stripe  = require('stripe');

describe('stripe: Service', function () {

  this.timeout(500);

  beforeEach(angular.mock.module(require('../')));

  var data, response, successMock, errorMock;
  beforeEach(function () {
    data = {};
    response = {};
    successMock = sinon.spy(function (data, callback) {
      $timeout(angular.bind(null, callback, 200, response));
    });
    errorMock = sinon.spy(function (data, callback) {
      $timeout(angular.bind(null, callback, 400, response));
    });
  });

  var stripe, $timeout;
  beforeEach(angular.mock.inject(function (_stripe_, _$timeout_) {
    stripe = _stripe_;
    $timeout = _$timeout_;
  }));

  var sandbox;
  beforeEach(function () {
    sandbox = sinon.sandbox.create();
  });

  afterEach(function () {
    sandbox.restore();
  });

  describe('card', function () {

    it('exposes helper methods', function () {
      expect(stripe.card.validateCardNumber).to.equal(Stripe.card.validateCardNumber);
      expect(stripe.card.validateExpiry).to.equal(Stripe.card.validateExpiry);
      expect(stripe.card.validateCVC).to.equal(Stripe.card.validateCVC);
      expect(stripe.card.cardType).to.equal(Stripe.card.cardType);
    });

    describe('#createToken', function () {

      it('calls the Stripe.js method with the data', function () {
        sandbox.stub(Stripe.card, 'createToken');
        stripe.card.createToken(data);
        expect(Stripe.card.createToken).to.have.been.calledWith(data);
      });

      it('resolves on success', function () {
        Stripe.card.createToken = successMock;
        expect(stripe.card.createToken(data))
          .to.eventually.equal(response);
        $timeout.flush();
      });

      it('rejects on error', function () {
        response.error = {
          code: 'invalid_expiry_year',
          message: 'Your card\'s expiration year is invalid.',
          param: 'exp_year',
          type: 'card_error'
        };
        Stripe.card.createToken = errorMock;
        expect(stripe.card.createToken())
          .to.be.rejected
          .then(function (err) {
            expect(err).to.contain(response.error)
          });
        $timeout.flush();
      });

    });

  });

  describe('bankAccount', function () {

    it('exposes helper methods', function () {
      expect(stripe.bankAccount.validateRoutingNumber).to.equal(Stripe.bankAccount.validateRoutingNumber);
      expect(stripe.bankAccount.validateAccountNumber).to.equal(Stripe.bankAccount.validateAccountNumber);
    });

    describe('#createToken', function () {

      it('calls the Stripe.js method with the data', function () {
        sandbox.stub(Stripe.bankAccount, 'createToken');
        stripe.bankAccount.createToken(data);
        expect(Stripe.bankAccount.createToken).to.have.been.calledWith(data);
      });

      it('resolves on success', function () {
        Stripe.bankAccount.createToken = successMock;
        expect(stripe.bankAccount.createToken(data))
          .to.eventually.equal(response);
        $timeout.flush();
      });

      it('rejects on error', function () {
        response.error = {
          message: 'Routing number must have 9 digits',
          param: 'bank_account',
          type: 'invalid_request_error'
        };
        Stripe.bankAccount.createToken = errorMock;
        expect(stripe.bankAccount.createToken())
          .to.be.rejected
          .then(function (err) {
            expect(err).to.contain(response.error)
          });
        $timeout.flush();
      });

    });

  });

});
<|endoftext|>


<commit_before>var http = require('http')
, path = require('path')
, fs = require('fs')
, url = require('url')
, dir = path.dirname(require.main.filename)
, requireAll = function(callback){
  if (typeof callback !== "function") callback = function(){}
  fs.readdir(dir,function(e,files){
    if (!e) files.forEach(function(filename,filenumber){
      var name = path.resolve(dir,filename)
      console.log(name)
      if (require.cache[name]) delete require.cache[name]
      try {
        require(name)
        console.log('Requiring '+name)
      }
      catch (e) {
        console.log('Error requiring '+name)
        console.log(e)
      }
      if (filenumber===files.length-1) callback()
    })
  })
}
module.exports = function(port){
  var args = Array.prototype.slice.call(arguments)
  fs.watch(dir,requireAll)
  requireAll(function(){
    http.createServer(function(req,res){
      var urlparts = url.parse(req.url).pathname.split('/').slice(1)
      , method = req.method.toLowerCase()
      , callback = function(data){
        if (typeof data === 'string') res.write(data)
        else {
          res.writeHead(200,{"Content-Type":"application/json"})
          res.write(JSON.stringify(data))
        }
        res.end()
      }
      if (typeof args[args.length-1]==='function') callback = function (data) {
        var newCallback = args.pop
        newCallback(data,callback)
      }
      if (urlparts[urlparts.length-1]==="") urlparts.pop()
      args.slice(1).forEach(function(arg){
        if (!urlparts.length) return
        if (require.cache[path.resolve(dir,urlparts[0]+".js")]) return
        this[arg] = urlparts.shift()
      })
      if ((modu=require.cache[path.resolve(dir,urlparts[0]+'.js')])) {
        modu.exports[method].apply(this,urlparts.slice(1).concat([callback]))
      }
      else require.main.exports[method].apply(this,urlparts.concat([callback]))
    }).listen(port)
  })
}
<commit_msg>except main module<commit_after>var http = require('http')
, path = require('path')
, fs = require('fs')
, url = require('url')
, dir = path.dirname(require.main.filename)
, requireAll = function(callback){
  if (typeof callback !== "function") callback = function(){}
  fs.readdir(dir,function(e,files){
    if (!e) files.forEach(function(filename,filenumber){
      var name = path.resolve(dir,filename)
      if (name === require.main.filename) return
      if (require.cache[name]) delete require.cache[name]
      try {
        require(name)
        console.log('Requiring '+name)
      }
      catch (e) {
        console.log('Error requiring '+name)
        console.log(e)
      }
      if (filenumber===files.length-1) callback()
    })
  })
}
module.exports = function(port){
  var args = Array.prototype.slice.call(arguments)
  fs.watch(dir,requireAll)
  requireAll(function(){
    http.createServer(function(req,res){
      var urlparts = url.parse(req.url).pathname.split('/').slice(1)
      , method = req.method.toLowerCase()
      , callback = function(data){
        if (typeof data === 'string') res.write(data)
        else {
          res.writeHead(200,{"Content-Type":"application/json"})
          res.write(JSON.stringify(data))
        }
        res.end()
      }
      if (typeof args[args.length-1]==='function') callback = function (data) {
        var newCallback = args.pop
        newCallback(data,callback)
      }
      if (urlparts[urlparts.length-1]==="") urlparts.pop()
      args.slice(1).forEach(function(arg){
        if (!urlparts.length) return
        if (require.cache[path.resolve(dir,urlparts[0]+".js")]) return
        this[arg] = urlparts.shift()
      })
      if ((modu=require.cache[path.resolve(dir,urlparts[0]+'.js')])) {
        modu.exports[method].apply(this,urlparts.slice(1).concat([callback]))
      }
      else require.main.exports[method].apply(this,urlparts.concat([callback]))
    }).listen(port)
  })
}
<|endoftext|>